@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
@@ -5,6 +5,7 @@ import { execSync as execSync2 } from "child_process";
5
5
  import * as fs3 from "fs";
6
6
  import * as os2 from "os";
7
7
  import * as path3 from "path";
8
+ import { _createCliContext as _createCliContext3, _createLogger } from "@stripe/extensibility-tool-utils";
8
9
 
9
10
  // src/custom-objects/build-definitions.ts
10
11
  import * as fs2 from "fs";
@@ -368,35 +369,35 @@ export default class MyBalanceApp implements Billing.CustomerBalanceApplication<
368
369
  `
369
370
  },
370
371
  {
371
- path: "extensions/billing.invoice_collection_setting/index.test.ts",
372
+ path: "extensions/billing.invoice_collection_options/index.test.ts",
372
373
  content: `import { beforeEach, describe, it, expect } from 'vitest';
373
374
 
374
- import MyInvoiceCollectionSetting from './index.js';
375
+ import MyInvoiceCollectionOptions from './index.js';
375
376
 
376
- describe('MyInvoiceCollectionSetting', () => {
377
- let instance: MyInvoiceCollectionSetting;
377
+ describe('MyInvoiceCollectionOptions', () => {
378
+ let instance: MyInvoiceCollectionOptions;
378
379
 
379
380
  beforeEach(() => {
380
- instance = new MyInvoiceCollectionSetting();
381
+ instance = new MyInvoiceCollectionOptions();
381
382
  });
382
383
 
383
384
  it('should be constructable', () => {
384
- expect(instance).toBeInstanceOf(MyInvoiceCollectionSetting);
385
+ expect(instance).toBeInstanceOf(MyInvoiceCollectionOptions);
385
386
  });
386
387
  });
387
388
  `
388
389
  },
389
390
  {
390
- path: "extensions/billing.invoice_collection_setting/index.ts",
391
+ path: "extensions/billing.invoice_collection_options/index.ts",
391
392
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
392
393
 
393
394
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
394
- interface MyInvoiceCollectionSettingConfig {}
395
+ interface MyInvoiceCollectionOptionsConfig {}
395
396
 
396
- export default class MyInvoiceCollectionSetting implements Billing.InvoiceCollectionSetting<MyInvoiceCollectionSettingConfig> {
397
- collectionOverride(
398
- _request: Billing.InvoiceCollectionSetting.InvoiceCollectionRequest,
399
- _config: MyInvoiceCollectionSettingConfig,
397
+ export default class MyInvoiceCollectionOptions implements Billing.InvoiceCollectionOptions<MyInvoiceCollectionOptionsConfig> {
398
+ overrideOptions(
399
+ _request: Billing.InvoiceCollectionOptions.InvoiceCollectionOptionsInput,
400
+ _config: MyInvoiceCollectionOptionsConfig,
400
401
  _context: Context
401
402
  ) {
402
403
  // TODO: implement your collection setting logic here
@@ -868,6 +869,99 @@ install-deps.log
868
869
 
869
870
  # generated schemas
870
871
  generated
872
+ `
873
+ },
874
+ {
875
+ path: "root/custom-objects/eslint.config.mts",
876
+ content: `import eslint from '@eslint/js';
877
+ import { defineConfig } from 'eslint/config';
878
+ import tseslint from 'typescript-eslint';
879
+ import eslintConfigPrettier from 'eslint-config-prettier/flat';
880
+
881
+ import globals from 'globals';
882
+
883
+ import stripeAppsConfig from '@stripe/extensibility-eslint-plugin';
884
+ import customObjectsConfig from '@stripe/extensibility-eslint-plugin/custom-objects';
885
+
886
+ export default defineConfig([
887
+ eslint.configs.recommended,
888
+ ...tseslint.configs.recommended,
889
+ ...stripeAppsConfig,
890
+ ...customObjectsConfig,
891
+
892
+ // Global ignores
893
+ {
894
+ ignores: ['dist', 'generated', 'node_modules'],
895
+ },
896
+
897
+ // TypeScript source files (with type-checking)
898
+ {
899
+ name: 'sources',
900
+ files: ['src/**/*.ts'],
901
+ ignores: ['**/*.test.ts', '**/__tests__/**'],
902
+ languageOptions: {
903
+ globals: {
904
+ ...globals.node,
905
+ },
906
+ parserOptions: {
907
+ projectService: true,
908
+ tsconfigRootDir: import.meta.dirname,
909
+ },
910
+ },
911
+ },
912
+
913
+ // Test files
914
+ {
915
+ name: 'tests',
916
+ files: ['src/**/*.test.ts', 'src/**/__tests__/**/*.ts'],
917
+ languageOptions: {
918
+ globals: {
919
+ ...globals.node,
920
+ },
921
+ parserOptions: {
922
+ projectService: true,
923
+ tsconfigRootDir: import.meta.dirname,
924
+ },
925
+ },
926
+ },
927
+
928
+ // Config files
929
+ {
930
+ name: 'ts-configs',
931
+ files: ['*.config.m?ts', 'eslint.config.mts'],
932
+ languageOptions: {
933
+ globals: {
934
+ ...globals.node,
935
+ },
936
+ parserOptions: {
937
+ projectService: false,
938
+ },
939
+ },
940
+ rules: {
941
+ '@typescript-eslint/no-unused-vars': 'off',
942
+ },
943
+ },
944
+
945
+ // JavaScript/MJS files (scripts, configs) \u2014 no TS project, so only
946
+ // disable the TS-parser-specific rule that doesn't apply without it.
947
+ {
948
+ name: 'js-configs',
949
+ files: ['**/*.js', '**/*.mjs'],
950
+ languageOptions: {
951
+ globals: {
952
+ ...globals.node,
953
+ },
954
+ parserOptions: {
955
+ projectService: false,
956
+ },
957
+ },
958
+ rules: {
959
+ '@typescript-eslint/no-require-imports': 'off',
960
+ },
961
+ },
962
+
963
+ eslintConfigPrettier,
964
+ ]);
871
965
  `
872
966
  },
873
967
  {
@@ -880,7 +974,9 @@ generated
880
974
  "private": true,
881
975
  "scripts": {
882
976
  "build": "test -d src && custom-objects-build --input src --output dist || true",
977
+ "lint": "pnpm lint:types && pnpm lint:eslint",
883
978
  "lint:types": "test ! -d src || tsc --noEmit",
979
+ "lint:eslint": "eslint .",
884
980
  "test": "vitest run"
885
981
  },
886
982
  "dependencies": {
@@ -903,8 +999,20 @@ generated
903
999
  "moduleResolution": "bundler",
904
1000
  "types": ["vitest/globals"]
905
1001
  },
1002
+ "include": ["src/**/*.ts"],
906
1003
  "exclude": ["dist"]
907
1004
  }
1005
+ `
1006
+ },
1007
+ {
1008
+ path: "root/custom-objects/vitest.config.mts",
1009
+ content: `import { defineConfig } from 'vitest/config';
1010
+
1011
+ export default defineConfig({
1012
+ test: {
1013
+ globals: true,
1014
+ },
1015
+ });
908
1016
  `
909
1017
  },
910
1018
  {
@@ -1022,7 +1130,7 @@ export default defineConfig([
1022
1130
  "build": "pnpm -r --if-present build",
1023
1131
  "lint": "pnpm lint:types && pnpm lint:eslint && pnpm lint:format",
1024
1132
  "lint:types": "pnpm -r --if-present lint:types",
1025
- "lint:eslint": "eslint . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present lint:eslint",
1133
+ "lint:eslint": "eslint . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present lint:eslint && pnpm -r --filter './custom-objects' --if-present lint:eslint",
1026
1134
  "lint:format": "prettier --check .",
1027
1135
  "fix:lint": "eslint --fix . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present fix:lint",
1028
1136
  "fix:format": "prettier --write .",
@@ -1068,7 +1176,7 @@ declarations:
1068
1176
  content: `#!/usr/bin/env tsx
1069
1177
  /**
1070
1178
  * Runs tests across the workspace:
1071
- * - vitest for script extensions and custom objects (extensions/*)
1179
+ * - vitest for script extensions (extensions/*) and custom objects (custom-objects/)
1072
1180
  * - jest for UI extensions (ui/)
1073
1181
  */
1074
1182
  import { existsSync, readdirSync } from 'node:fs';
@@ -1078,6 +1186,8 @@ const hasExtensions =
1078
1186
  existsSync('extensions') &&
1079
1187
  readdirSync('extensions').some((name) => existsSync(\`extensions/\${name}/package.json\`));
1080
1188
 
1189
+ const hasCustomObjects = existsSync('custom-objects/package.json');
1190
+
1081
1191
  const hasUI = existsSync('ui/package.json');
1082
1192
 
1083
1193
  let exitCode = 0;
@@ -1090,7 +1200,7 @@ function run(cmd: string): void {
1090
1200
  }
1091
1201
  }
1092
1202
 
1093
- if (hasExtensions) {
1203
+ if (hasExtensions || hasCustomObjects) {
1094
1204
  run('vitest run');
1095
1205
  }
1096
1206
 
@@ -1242,8 +1352,30 @@ function _devNpmDep(name, version) {
1242
1352
  return { type: "dev-npm", name, version };
1243
1353
  }
1244
1354
 
1355
+ // src/workspace-versions.json
1356
+ var workspace_versions_default = {
1357
+ "@stripe/extensibility-custom-objects": "0.8.0",
1358
+ "@stripe/extensibility-custom-objects-tools": "0.42.1",
1359
+ "@stripe/extensibility-dev-tools": "0.25.1",
1360
+ "@stripe/extensibility-eslint-plugin": "0.17.1",
1361
+ "@stripe/extensibility-language-server": "0.3.4",
1362
+ "@stripe/extensibility-sdk": "0.27.1",
1363
+ "@stripe/extensibility-test-helpers": "0.2.7"
1364
+ };
1365
+
1366
+ // src/workspace-versions.ts
1367
+ var _workspaceVersions = workspace_versions_default;
1368
+ function _workspaceVersion(packageName) {
1369
+ const v = _workspaceVersions[packageName];
1370
+ if (v === void 0) {
1371
+ throw new Error(
1372
+ `Unknown workspace package "${packageName}". Check workspace-versions.json or run: tsx scripts/src/sync-workspace-versions.ts`
1373
+ );
1374
+ }
1375
+ return v;
1376
+ }
1377
+
1245
1378
  // src/templates/extensions/base.ts
1246
- import { _workspaceVersion } from "@stripe/extensibility-tool-utils";
1247
1379
  var SDK_PACKAGE_NAME = "@stripe/extensibility-sdk";
1248
1380
  var LANGUAGE_SERVER_PACKAGE_NAME = "@stripe/extensibility-language-server";
1249
1381
  var LANGUAGE_SERVER_PACKAGE_VERSION = `^${_workspaceVersion(LANGUAGE_SERVER_PACKAGE_NAME)}`;
@@ -1548,14 +1680,14 @@ var billing_bill_discount_calculation_default = {
1548
1680
  [EXTENSION_INTERFACE_ID5]: discountCalculationTemplate
1549
1681
  };
1550
1682
 
1551
- // src/templates/extensions/billing.invoice_collection_setting.ts
1552
- var EXTENSION_INTERFACE_ID6 = "billing.invoice_collection_setting";
1553
- var invoiceCollectionSettingTemplate = {
1683
+ // src/templates/extensions/billing.invoice_collection_options.ts
1684
+ var EXTENSION_INTERFACE_ID6 = "billing.invoice_collection_options";
1685
+ var invoiceCollectionOptionsTemplate = {
1554
1686
  hidden: true,
1555
1687
  methods: {
1556
- collection_override: { implementation_types: ["script"] }
1688
+ override_options: { implementation_types: ["script"] }
1557
1689
  },
1558
- description: "Use Stripe Scripts to create custom invoice collection logic that controls how your integration handles invoices generated from subscriptions.",
1690
+ description: "Use Stripe Scripts to create custom invoice collection options that controls how your integration handles invoices generated from subscriptions.",
1559
1691
  generate: (params, context) => {
1560
1692
  const { id } = params;
1561
1693
  const { fs: fs4 } = context;
@@ -1583,15 +1715,15 @@ var invoiceCollectionSettingTemplate = {
1583
1715
  ...base.files
1584
1716
  ],
1585
1717
  methods: {
1586
- collection_override: {
1718
+ override_options: {
1587
1719
  implementation_type: "script"
1588
1720
  }
1589
1721
  }
1590
1722
  };
1591
1723
  }
1592
1724
  };
1593
- var billing_invoice_collection_setting_default = {
1594
- [EXTENSION_INTERFACE_ID6]: invoiceCollectionSettingTemplate
1725
+ var billing_invoice_collection_options_default = {
1726
+ [EXTENSION_INTERFACE_ID6]: invoiceCollectionOptionsTemplate
1595
1727
  };
1596
1728
 
1597
1729
  // src/templates/extensions/billing.prorations.ts
@@ -1699,7 +1831,7 @@ var DEFAULT_TEMPLATES = {
1699
1831
  ...extend_workflows_custom_action_default,
1700
1832
  ...billing_customer_balance_application_default,
1701
1833
  ...billing_bill_discount_calculation_default,
1702
- ...billing_invoice_collection_setting_default,
1834
+ ...billing_invoice_collection_options_default,
1703
1835
  ...billing_prorations_default,
1704
1836
  ...billing_recurring_billing_item_handling_default
1705
1837
  };
@@ -1765,10 +1897,11 @@ function mapActions(actions) {
1765
1897
  }
1766
1898
  function mapProperties(schema) {
1767
1899
  const result = {};
1768
- const requiredSet = new Set(schema?.required ?? []);
1769
- if (!schema?.properties) return result;
1770
- const defs = schema.$defs ?? {};
1771
- for (const [key, propSchema] of Object.entries(schema.properties)) {
1900
+ const resolvedSchema = schema === null || schema === void 0 ? schema : resolveRef(schema, schema.$defs ?? {});
1901
+ const requiredSet = new Set(resolvedSchema?.required ?? []);
1902
+ if (!resolvedSchema?.properties) return result;
1903
+ const defs = resolvedSchema.$defs ?? {};
1904
+ for (const [key, propSchema] of Object.entries(resolvedSchema.properties)) {
1772
1905
  result[key] = toFieldSchema(resolveRef(propSchema, defs), requiredSet.has(key));
1773
1906
  }
1774
1907
  return result;
@@ -1812,10 +1945,11 @@ function toFieldSchema(schema, required) {
1812
1945
  fieldSchema.valuesPresence = FieldPresence.PRESENT;
1813
1946
  }
1814
1947
  if (schema.default !== void 0) {
1815
- if (dataType === DataType.ENUM_TYPE && enumValues && (typeof schema.default !== "string" || !enumValues.includes(schema.default))) {
1816
- throw new Error(
1817
- `Default value ${JSON.stringify(schema.default)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
1818
- );
1948
+ if (dataType === DataType.ENUM_TYPE && enumValues) {
1949
+ validateEnumDefault(schema.default, enumValues);
1950
+ }
1951
+ if (dataType === DataType.DATETIME_TYPE) {
1952
+ validateDatetimeDefault(schema.default);
1819
1953
  }
1820
1954
  fieldSchema.default = toDefaultValue(schema.default, dataType);
1821
1955
  }
@@ -1829,7 +1963,6 @@ function resolveDataType(schema, enumValues, refTarget) {
1829
1963
  if (schema.format === "date-time") return DataType.DATETIME_TYPE;
1830
1964
  return DataType.STRING_TYPE;
1831
1965
  case "integer":
1832
- case "number":
1833
1966
  return DataType.INTEGER_TYPE;
1834
1967
  case "boolean":
1835
1968
  return DataType.BOOLEAN_TYPE;
@@ -1866,14 +1999,31 @@ function extractSingleLiteral(schema) {
1866
1999
  return null;
1867
2000
  }
1868
2001
  function extractEnumValues(schema) {
1869
- if (schema.enum) {
2002
+ if (Array.isArray(schema.enum) && schema.enum.every((value) => typeof value === "string")) {
1870
2003
  return schema.enum.map(String);
1871
2004
  }
1872
- if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every((item) => "const" in item)) {
2005
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every(
2006
+ (item) => "const" in item && typeof item.const === "string"
2007
+ )) {
1873
2008
  return schema.oneOf.map((item) => String(item.const));
1874
2009
  }
1875
2010
  return null;
1876
2011
  }
2012
+ function validateEnumDefault(value, enumValues) {
2013
+ if (typeof value !== "string" || !enumValues.includes(value)) {
2014
+ throw new Error(
2015
+ `Default value ${JSON.stringify(value)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
2016
+ );
2017
+ }
2018
+ }
2019
+ var DATETIME_UTC_MS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|\+00:00)$/;
2020
+ function validateDatetimeDefault(value) {
2021
+ if (typeof value !== "string" || !DATETIME_UTC_MS_RE.test(value)) {
2022
+ throw new Error(
2023
+ `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`
2024
+ );
2025
+ }
2026
+ }
1877
2027
  function toValueBoundary(value) {
1878
2028
  if (!Number.isInteger(value)) {
1879
2029
  throw new Error(
@@ -1889,7 +2039,15 @@ function toDefaultValue(value, dataType) {
1889
2039
  if (dataType === DataType.ENUM_TYPE && typeof value === "string") {
1890
2040
  return { stringDefault: value };
1891
2041
  }
2042
+ if (dataType === DataType.DATETIME_TYPE && typeof value === "string") {
2043
+ return { stringDefault: value };
2044
+ }
1892
2045
  if (dataType === DataType.INTEGER_TYPE && typeof value === "number") {
2046
+ if (!Number.isInteger(value)) {
2047
+ throw new Error(
2048
+ `Integer default values must be whole numbers, got ${JSON.stringify(value)}.`
2049
+ );
2050
+ }
1893
2051
  return { integerDefault: value };
1894
2052
  }
1895
2053
  if (dataType === DataType.BOOLEAN_TYPE && typeof value === "boolean") {
@@ -1925,7 +2083,7 @@ async function analyzeAndInjectManifest(options) {
1925
2083
  (diagnostic) => diagnostic.severity === "error"
1926
2084
  );
1927
2085
  if (errorDiagnostics.length > 0) {
1928
- const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("; ");
2086
+ const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("\n");
1929
2087
  throw new Error(details);
1930
2088
  }
1931
2089
  const coPackageJsonPath = path2.join(projectRoot, "custom-objects", "package.json");
@@ -2062,16 +2220,18 @@ function readPackageDependencies(packageJsonPath) {
2062
2220
  }
2063
2221
 
2064
2222
  // src/bin/create-upload-image.ts
2223
+ var logger = _createLogger({ name: "create-upload-image" });
2065
2224
  async function main() {
2225
+ const ctx = _createCliContext3();
2066
2226
  const targetPath = process.argv[2];
2067
2227
  if (!targetPath) {
2068
- console.error("Usage: create-upload-image <target-path>");
2228
+ ctx.ux.error("Usage: create-upload-image <target-path>");
2069
2229
  process.exit(1);
2070
2230
  }
2071
2231
  let state = null;
2072
2232
  const manifestPath = "stripe-app.yaml";
2073
2233
  if (fs3.existsSync(manifestPath)) {
2074
- state = await analyzeAndInjectManifest({ manifestPath });
2234
+ state = await analyzeAndInjectManifest({ manifestPath, context: ctx });
2075
2235
  }
2076
2236
  fs3.mkdirSync(targetPath, { recursive: true });
2077
2237
  const tarball = path3.join(os2.tmpdir(), `upload-image-${String(Date.now())}.tgz`);
@@ -2104,7 +2264,7 @@ async function main() {
2104
2264
  }
2105
2265
  }
2106
2266
  if (state) {
2107
- await writeCustomObjectArtifacts({ targetPath }, state);
2267
+ await writeCustomObjectArtifacts({ targetPath, context: ctx }, state);
2108
2268
  }
2109
2269
  const imageMetadata = JSON.stringify(
2110
2270
  { image: { version: "1.0", built: (/* @__PURE__ */ new Date()).toISOString() } },
@@ -2114,6 +2274,6 @@ async function main() {
2114
2274
  fs3.writeFileSync(path3.join(targetPath, ".image.json"), imageMetadata + "\n");
2115
2275
  }
2116
2276
  main().catch((err) => {
2117
- console.error(err);
2277
+ logger.error({ err }, "Unexpected error");
2118
2278
  process.exit(1);
2119
2279
  });