@stripe/extensibility-dev-tools 0.23.5
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.
- package/LICENSE.md +19 -0
- package/dist/bin/build-custom-object-definitions.cjs +2111 -0
- package/dist/bin/build-custom-object-definitions.d.ts +11 -0
- package/dist/bin/build-custom-object-definitions.d.ts.map +1 -0
- package/dist/bin/build-custom-object-definitions.js +2088 -0
- package/dist/bin/create-upload-image.cjs +2136 -0
- package/dist/bin/create-upload-image.d.ts +17 -0
- package/dist/bin/create-upload-image.d.ts.map +1 -0
- package/dist/bin/create-upload-image.js +2113 -0
- package/dist/bin/dev-tools-rpc.cjs +3874 -0
- package/dist/bin/dev-tools-rpc.d.ts +3 -0
- package/dist/bin/dev-tools-rpc.d.ts.map +1 -0
- package/dist/bin/dev-tools-rpc.js +3864 -0
- package/dist/bin/gen-schemas.cjs +20739 -0
- package/dist/bin/gen-schemas.d.ts +8 -0
- package/dist/bin/gen-schemas.d.ts.map +1 -0
- package/dist/bin/gen-schemas.js +20715 -0
- package/dist/bin/gen-workspace.cjs +3847 -0
- package/dist/bin/gen-workspace.d.ts +8 -0
- package/dist/bin/gen-workspace.d.ts.map +1 -0
- package/dist/bin/gen-workspace.js +3841 -0
- package/dist/bin/manifest.cjs +686 -0
- package/dist/bin/manifest.d.ts +10 -0
- package/dist/bin/manifest.d.ts.map +1 -0
- package/dist/bin/manifest.js +663 -0
- package/dist/bin/rpc/dispatch.d.ts +10 -0
- package/dist/bin/rpc/dispatch.d.ts.map +1 -0
- package/dist/bin/rpc/handlers.d.ts +4 -0
- package/dist/bin/rpc/handlers.d.ts.map +1 -0
- package/dist/bin/rpc/types.d.ts +29 -0
- package/dist/bin/rpc/types.d.ts.map +1 -0
- package/dist/bin/template-info.cjs +1511 -0
- package/dist/bin/template-info.d.ts +9 -0
- package/dist/bin/template-info.d.ts.map +1 -0
- package/dist/bin/template-info.js +1488 -0
- package/dist/custom-objects/build-definitions.d.ts +98 -0
- package/dist/custom-objects/build-definitions.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/custom_objects/pub/api/app_api/object_definitions_app_service.pb.d.ts +191 -0
- package/dist/custom-objects/generated/proto/custom_objects/pub/api/app_api/object_definitions_app_service.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/custom_objects/pub/api/common/schema.pb.d.ts +131 -0
- package/dist/custom-objects/generated/proto/custom_objects/pub/api/common/schema.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/google/protobuf/descriptor.pb.d.ts +1482 -0
- package/dist/custom-objects/generated/proto/google/protobuf/descriptor.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/google/protobuf/timestamp.pb.d.ts +167 -0
- package/dist/custom-objects/generated/proto/google/protobuf/timestamp.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/proto/annotations.pb.d.ts +64 -0
- package/dist/custom-objects/generated/proto/proto/annotations.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/proto/extensions.pb.d.ts +657 -0
- package/dist/custom-objects/generated/proto/proto/extensions.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/metadata/pub/api/api_metadata.pb.d.ts +105 -0
- package/dist/custom-objects/generated/proto/vendor/metadata/pub/api/api_metadata.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/net/idempotency/idempotency_model.pb.d.ts +79 -0
- package/dist/custom-objects/generated/proto/vendor/net/idempotency/idempotency_model.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/api_group_enum.pb.d.ts +129 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/api_group_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/api_visibility.pb.d.ts +76 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/api_visibility.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/customize_dispatch_middleware_enum.pb.d.ts +78 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/customize_dispatch_middleware_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/docs_namespace_group_enum.pb.d.ts +146 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/docs_namespace_group_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/documented_enum.pb.d.ts +76 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/documented_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/event_scope_enum.pb.d.ts +92 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/event_scope_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/extension_interface.pb.d.ts +124 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/extension_interface.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/feature_enum.pb.d.ts +1070 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/feature_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/field_validation_rules.pb.d.ts +279 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/field_validation_rules.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/flavor_enum.pb.d.ts +78 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/flavor_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/http_error_status.pb.d.ts +102 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/http_error_status.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/method_kind_enum.pb.d.ts +86 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/method_kind_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/method_priority.pb.d.ts +80 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/method_priority.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/permission_check_enum.pb.d.ts +74 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/permission_check_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/redaction_enum.pb.d.ts +76 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/redaction_enum.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/region_routers.pb.d.ts +103 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/region_routers.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/rollout_configs.pb.d.ts +153 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/rollout_configs.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/v2ext.pb.d.ts +1111 -0
- package/dist/custom-objects/generated/proto/vendor/publicapi/v2ext.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/vext/annotations.pb.d.ts +602 -0
- package/dist/custom-objects/generated/proto/vendor/vext/annotations.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/vext/extensions.pb.d.ts +144 -0
- package/dist/custom-objects/generated/proto/vendor/vext/extensions.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/vext/privacy_unified_annotations.pb.d.ts +851 -0
- package/dist/custom-objects/generated/proto/vendor/vext/privacy_unified_annotations.pb.d.ts.map +1 -0
- package/dist/custom-objects/generated/proto/vendor/vext/xml_annotations.pb.d.ts +125 -0
- package/dist/custom-objects/generated/proto/vendor/vext/xml_annotations.pb.d.ts.map +1 -0
- package/dist/custom-objects/to-proto-json.d.ts +17 -0
- package/dist/custom-objects/to-proto-json.d.ts.map +1 -0
- package/dist/dependencies/index.cjs +601 -0
- package/dist/dependencies/index.d.ts +320 -0
- package/dist/dependencies/index.d.ts.map +1 -0
- package/dist/dependencies/index.js +560 -0
- package/dist/extensibility-dev-tools-alpha.d.ts +199 -0
- package/dist/extensibility-dev-tools-beta.d.ts +199 -0
- package/dist/extensibility-dev-tools-dependencies-alpha.d.ts +51 -0
- package/dist/extensibility-dev-tools-dependencies-beta.d.ts +51 -0
- package/dist/extensibility-dev-tools-dependencies-internal.d.ts +372 -0
- package/dist/extensibility-dev-tools-dependencies-public.d.ts +51 -0
- package/dist/extensibility-dev-tools-internal.d.ts +1722 -0
- package/dist/extensibility-dev-tools-jsonschema-tools-alpha.d.ts +57 -0
- package/dist/extensibility-dev-tools-jsonschema-tools-beta.d.ts +57 -0
- package/dist/extensibility-dev-tools-jsonschema-tools-internal.d.ts +123 -0
- package/dist/extensibility-dev-tools-jsonschema-tools-public.d.ts +57 -0
- package/dist/extensibility-dev-tools-manifest-alpha.d.ts +31 -0
- package/dist/extensibility-dev-tools-manifest-beta.d.ts +31 -0
- package/dist/extensibility-dev-tools-manifest-internal.d.ts +461 -0
- package/dist/extensibility-dev-tools-manifest-public.d.ts +31 -0
- package/dist/extensibility-dev-tools-public.d.ts +199 -0
- package/dist/extensibility-dev-tools-schemas-alpha.d.ts +9 -0
- package/dist/extensibility-dev-tools-schemas-beta.d.ts +9 -0
- package/dist/extensibility-dev-tools-schemas-internal.d.ts +41 -0
- package/dist/extensibility-dev-tools-schemas-public.d.ts +9 -0
- package/dist/extensibility-dev-tools-templates-alpha.d.ts +67 -0
- package/dist/extensibility-dev-tools-templates-beta.d.ts +67 -0
- package/dist/extensibility-dev-tools-templates-internal.d.ts +554 -0
- package/dist/extensibility-dev-tools-templates-public.d.ts +67 -0
- package/dist/extensibility-dev-tools-workspace-alpha.d.ts +51 -0
- package/dist/extensibility-dev-tools-workspace-beta.d.ts +51 -0
- package/dist/extensibility-dev-tools-workspace-internal.d.ts +410 -0
- package/dist/extensibility-dev-tools-workspace-public.d.ts +51 -0
- package/dist/index.cjs +3810 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3758 -0
- package/dist/jsonschema-tools.cjs +20451 -0
- package/dist/jsonschema-tools.d.ts +98 -0
- package/dist/jsonschema-tools.d.ts.map +1 -0
- package/dist/jsonschema-tools.js +20404 -0
- package/dist/manifest/index.cjs +610 -0
- package/dist/manifest/index.d.ts +8 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +571 -0
- package/dist/manifest/manifest-v1.d.ts +102 -0
- package/dist/manifest/manifest-v1.d.ts.map +1 -0
- package/dist/manifest/manifest-v2.d.ts +253 -0
- package/dist/manifest/manifest-v2.d.ts.map +1 -0
- package/dist/manifest/stripe-app-manifest.d.ts +114 -0
- package/dist/manifest/stripe-app-manifest.d.ts.map +1 -0
- package/dist/schemas/index.cjs +20692 -0
- package/dist/schemas/index.d.ts +37 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +20656 -0
- package/dist/templates/diff-viewer/diff-generator.d.ts +22 -0
- package/dist/templates/diff-viewer/diff-generator.d.ts.map +1 -0
- package/dist/templates/diff-viewer/diff-prompt.d.ts +13 -0
- package/dist/templates/diff-viewer/diff-prompt.d.ts.map +1 -0
- package/dist/templates/diff-viewer/index.d.ts +7 -0
- package/dist/templates/diff-viewer/index.d.ts.map +1 -0
- package/dist/templates/diff-viewer/terminal-renderer.d.ts +29 -0
- package/dist/templates/diff-viewer/terminal-renderer.d.ts.map +1 -0
- package/dist/templates/diff-viewer/types.d.ts +58 -0
- package/dist/templates/diff-viewer/types.d.ts.map +1 -0
- package/dist/templates/extensions/base.d.ts +23 -0
- package/dist/templates/extensions/base.d.ts.map +1 -0
- package/dist/templates/extensions/billing.bill.discount_calculation.d.ts +6 -0
- package/dist/templates/extensions/billing.bill.discount_calculation.d.ts.map +1 -0
- package/dist/templates/extensions/billing.customer_balance_application.d.ts +6 -0
- package/dist/templates/extensions/billing.customer_balance_application.d.ts.map +1 -0
- package/dist/templates/extensions/billing.invoice_collection_setting.d.ts +6 -0
- package/dist/templates/extensions/billing.invoice_collection_setting.d.ts.map +1 -0
- package/dist/templates/extensions/billing.prorations.d.ts +6 -0
- package/dist/templates/extensions/billing.prorations.d.ts.map +1 -0
- package/dist/templates/extensions/billing.recurring_billing_item_handling.d.ts +6 -0
- package/dist/templates/extensions/billing.recurring_billing_item_handling.d.ts.map +1 -0
- package/dist/templates/extensions/core.workflows.custom_action.d.ts +6 -0
- package/dist/templates/extensions/core.workflows.custom_action.d.ts.map +1 -0
- package/dist/templates/extensions/extend.objects.custom_objects.d.ts +6 -0
- package/dist/templates/extensions/extend.objects.custom_objects.d.ts.map +1 -0
- package/dist/templates/extensions/extend.workflows.custom_action.d.ts +6 -0
- package/dist/templates/extensions/extend.workflows.custom_action.d.ts.map +1 -0
- package/dist/templates/extensions/index.d.ts +13 -0
- package/dist/templates/extensions/index.d.ts.map +1 -0
- package/dist/templates/extensions/registry.d.ts +10 -0
- package/dist/templates/extensions/registry.d.ts.map +1 -0
- package/dist/templates/extensions/types.d.ts +104 -0
- package/dist/templates/extensions/types.d.ts.map +1 -0
- package/dist/templates/file-writer.d.ts +140 -0
- package/dist/templates/file-writer.d.ts.map +1 -0
- package/dist/templates/fs/_impl.d.ts +29 -0
- package/dist/templates/fs/_impl.d.ts.map +1 -0
- package/dist/templates/fs/filesystem.d.ts +8 -0
- package/dist/templates/fs/filesystem.d.ts.map +1 -0
- package/dist/templates/fs/in-memory.d.ts +9 -0
- package/dist/templates/fs/in-memory.d.ts.map +1 -0
- package/dist/templates/fs/index.d.ts +25 -0
- package/dist/templates/fs/index.d.ts.map +1 -0
- package/dist/templates/fs-utils.d.ts +17 -0
- package/dist/templates/fs-utils.d.ts.map +1 -0
- package/dist/templates/index.cjs +2248 -0
- package/dist/templates/index.d.ts +32 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +2203 -0
- package/dist/templates/root/index.d.ts +60 -0
- package/dist/templates/root/index.d.ts.map +1 -0
- package/dist/templates/simple-templates.d.ts +8 -0
- package/dist/templates/simple-templates.d.ts.map +1 -0
- package/dist/templates/template-manager.d.ts +8 -0
- package/dist/templates/template-manager.d.ts.map +1 -0
- package/dist/templates/types.d.ts +9 -0
- package/dist/templates/types.d.ts.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/workspace/index.cjs +3756 -0
- package/dist/workspace/index.d.ts +336 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +3731 -0
- package/package.json +137 -0
- package/templates/extensions/billing.bill.discount_calculation/index.test.ts +15 -0
- package/templates/extensions/billing.bill.discount_calculation/index.ts +20 -0
- package/templates/extensions/billing.customer_balance_application/index.test.ts +15 -0
- package/templates/extensions/billing.customer_balance_application/index.ts +18 -0
- package/templates/extensions/billing.invoice_collection_setting/index.test.ts +15 -0
- package/templates/extensions/billing.invoice_collection_setting/index.ts +16 -0
- package/templates/extensions/billing.prorations/index.test.ts +15 -0
- package/templates/extensions/billing.prorations/index.ts +18 -0
- package/templates/extensions/billing.recurring_billing_item_handling/index.test.ts +15 -0
- package/templates/extensions/billing.recurring_billing_item_handling/index.ts +42 -0
- package/templates/extensions/common/.prettierignore +3 -0
- package/templates/extensions/common/eslint.config.mts.mustache +95 -0
- package/templates/extensions/common/package.json.mustache +26 -0
- package/templates/extensions/common/tsconfig.build.json.mustache +15 -0
- package/templates/extensions/common/tsconfig.json.mustache +16 -0
- package/templates/extensions/core.workflows.custom_action/custom_input.schema.json +6 -0
- package/templates/extensions/core.workflows.custom_action/index.test.ts +15 -0
- package/templates/extensions/core.workflows.custom_action/index.ts +31 -0
- package/templates/extensions/extend.workflows.custom_action/custom_input.schema.json +6 -0
- package/templates/extensions/extend.workflows.custom_action/index.test.ts +15 -0
- package/templates/extensions/extend.workflows.custom_action/index.ts +31 -0
- package/templates/root/.husky/pre-commit +1 -0
- package/templates/root/.prettierignore +5 -0
- package/templates/root/.prettierrc +7 -0
- package/templates/root/_gitignore +28 -0
- package/templates/root/custom-objects/package.json +20 -0
- package/templates/root/custom-objects/tsconfig.json +9 -0
- package/templates/root/eslint.config.mts +95 -0
- package/templates/root/package.json.mustache +32 -0
- package/templates/root/pnpm-workspace.yaml +7 -0
- package/templates/root/stripe-app.yaml.mustache +6 -0
- package/templates/root/tools/test.mts +38 -0
- package/templates/root/tsconfig.base.json +23 -0
- package/templates/root/tsconfig.json +15 -0
- package/templates/root/ui/package.json +17 -0
- package/templates/root/vitest.config.mts +47 -0
|
@@ -0,0 +1,2203 @@
|
|
|
1
|
+
// src/templates/template-manager.ts
|
|
2
|
+
import { _TemplateManager } from "@stripe/extensibility-tool-utils";
|
|
3
|
+
|
|
4
|
+
// src/templates/fs/in-memory.ts
|
|
5
|
+
import { _createInMemoryTemplateFS } from "@stripe/extensibility-tool-utils";
|
|
6
|
+
|
|
7
|
+
// templates-virtual:./_impl.js
|
|
8
|
+
var TEMPLATE_FS_IMAGE = [
|
|
9
|
+
{
|
|
10
|
+
path: "extensions/billing.bill.discount_calculation/index.test.ts",
|
|
11
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
12
|
+
|
|
13
|
+
import MyDiscountCalculation from './index.js';
|
|
14
|
+
|
|
15
|
+
describe('MyDiscountCalculation', () => {
|
|
16
|
+
let instance: MyDiscountCalculation;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
instance = new MyDiscountCalculation();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should be constructable', () => {
|
|
23
|
+
expect(instance).toBeInstanceOf(MyDiscountCalculation);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
`
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
path: "extensions/billing.bill.discount_calculation/index.ts",
|
|
30
|
+
content: `import type { Billing } from '@stripe/extensibility-sdk/extensions';
|
|
31
|
+
import type { Context } from '@stripe/extensibility-sdk/extensions';
|
|
32
|
+
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
34
|
+
interface MyDiscountCalculationConfig extends Record<string, unknown> {}
|
|
35
|
+
|
|
36
|
+
export default class MyDiscountCalculation implements Billing.Bill
|
|
37
|
+
.DiscountCalculation<MyDiscountCalculationConfig> {
|
|
38
|
+
computeDiscounts(
|
|
39
|
+
request: Billing.Bill.DiscountCalculation.DiscountableItem,
|
|
40
|
+
_config: MyDiscountCalculationConfig,
|
|
41
|
+
_context: Context
|
|
42
|
+
) {
|
|
43
|
+
// TODO: implement your discount logic here
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
discount: { amount: request.grossAmount },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
path: "extensions/billing.customer_balance_application/index.test.ts",
|
|
54
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
55
|
+
|
|
56
|
+
import MyCustomerBalanceApplication from './index.js';
|
|
57
|
+
|
|
58
|
+
describe('MyCustomerBalanceApplication', () => {
|
|
59
|
+
let instance: MyCustomerBalanceApplication;
|
|
60
|
+
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
instance = new MyCustomerBalanceApplication();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should be constructable', () => {
|
|
66
|
+
expect(instance).toBeInstanceOf(MyCustomerBalanceApplication);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
`
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
path: "extensions/billing.customer_balance_application/index.ts",
|
|
73
|
+
content: `import type { Billing, Context } from '@stripe/extensibility-sdk/extensions';
|
|
74
|
+
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
76
|
+
interface MyCustomerBalanceApplicationConfig extends Record<string, unknown> {}
|
|
77
|
+
|
|
78
|
+
export default class MyCustomerBalanceApplication implements Billing.CustomerBalanceApplication<MyCustomerBalanceApplicationConfig> {
|
|
79
|
+
computeAppliedCustomerBalance(
|
|
80
|
+
request: Billing.CustomerBalanceApplication.CustomerBalanceApplicationInput,
|
|
81
|
+
_config: MyCustomerBalanceApplicationConfig,
|
|
82
|
+
_context: Context
|
|
83
|
+
) {
|
|
84
|
+
// TODO: implement your customer balance logic here
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
appliedCustomerBalance: request.customerBalance,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
`
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
path: "extensions/billing.invoice_collection_setting/index.test.ts",
|
|
95
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
96
|
+
|
|
97
|
+
import MyInvoiceCollectionSetting from './index.js';
|
|
98
|
+
|
|
99
|
+
describe('MyInvoiceCollectionSetting', () => {
|
|
100
|
+
let instance: MyInvoiceCollectionSetting;
|
|
101
|
+
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
instance = new MyInvoiceCollectionSetting();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should be constructable', () => {
|
|
107
|
+
expect(instance).toBeInstanceOf(MyInvoiceCollectionSetting);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
`
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
path: "extensions/billing.invoice_collection_setting/index.ts",
|
|
114
|
+
content: `import type { Billing, Context } from '@stripe/extensibility-sdk/extensions';
|
|
115
|
+
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
117
|
+
interface MyInvoiceCollectionSettingConfig extends Record<string, unknown> {}
|
|
118
|
+
|
|
119
|
+
export default class MyInvoiceCollectionSetting implements Billing.InvoiceCollectionSetting<MyInvoiceCollectionSettingConfig> {
|
|
120
|
+
collectionOverride(
|
|
121
|
+
_request: Billing.InvoiceCollectionSetting.InvoiceCollectionRequest,
|
|
122
|
+
_config: MyInvoiceCollectionSettingConfig,
|
|
123
|
+
_context: Context
|
|
124
|
+
) {
|
|
125
|
+
// TODO: implement your collection setting logic here
|
|
126
|
+
|
|
127
|
+
return {};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
`
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
path: "extensions/billing.prorations/index.test.ts",
|
|
134
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
135
|
+
|
|
136
|
+
import MyProrations from './index.js';
|
|
137
|
+
|
|
138
|
+
describe('MyProrations', () => {
|
|
139
|
+
let instance: MyProrations;
|
|
140
|
+
|
|
141
|
+
beforeEach(() => {
|
|
142
|
+
instance = new MyProrations();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should be constructable', () => {
|
|
146
|
+
expect(instance).toBeInstanceOf(MyProrations);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
`
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
path: "extensions/billing.prorations/index.ts",
|
|
153
|
+
content: `import type { Billing, Context } from '@stripe/extensibility-sdk/extensions';
|
|
154
|
+
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
156
|
+
interface MyProrationsConfig extends Record<string, unknown> {}
|
|
157
|
+
|
|
158
|
+
export default class MyProrations implements Billing.Prorations<MyProrationsConfig> {
|
|
159
|
+
prorateItems(
|
|
160
|
+
_request: Billing.Prorations.ProrateItemsInput,
|
|
161
|
+
_config: MyProrationsConfig,
|
|
162
|
+
_context: Context
|
|
163
|
+
) {
|
|
164
|
+
// TODO: implement your proration logic here
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
items: [],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
`
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
path: "extensions/billing.recurring_billing_item_handling/index.test.ts",
|
|
175
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
176
|
+
|
|
177
|
+
import MyRecurringBillingItemHandling from './index.js';
|
|
178
|
+
|
|
179
|
+
describe('MyRecurringBillingItemHandling', () => {
|
|
180
|
+
let instance: MyRecurringBillingItemHandling;
|
|
181
|
+
|
|
182
|
+
beforeEach(() => {
|
|
183
|
+
instance = new MyRecurringBillingItemHandling();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should be constructable', () => {
|
|
187
|
+
expect(instance).toBeInstanceOf(MyRecurringBillingItemHandling);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
`
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
path: "extensions/billing.recurring_billing_item_handling/index.ts",
|
|
194
|
+
content: `import type { Billing, Context } from '@stripe/extensibility-sdk/extensions';
|
|
195
|
+
|
|
196
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
197
|
+
interface MyRecurringBillingItemHandlingConfig extends Record<string, unknown> {}
|
|
198
|
+
|
|
199
|
+
export default class MyRecurringBillingItemHandling implements Billing.RecurringBillingItemHandling<MyRecurringBillingItemHandlingConfig> {
|
|
200
|
+
beforeItemCreation(
|
|
201
|
+
_request: Billing.RecurringBillingItemHandling.BeforeItemCreationInput,
|
|
202
|
+
_config: MyRecurringBillingItemHandlingConfig,
|
|
203
|
+
_context: Context
|
|
204
|
+
) {
|
|
205
|
+
// TODO: implement your before-item-creation logic here
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
items: [],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
filterItems(
|
|
213
|
+
_request: Billing.RecurringBillingItemHandling.FilterItemsInput,
|
|
214
|
+
_config: MyRecurringBillingItemHandlingConfig,
|
|
215
|
+
_context: Context
|
|
216
|
+
) {
|
|
217
|
+
// TODO: implement your filter-items logic here
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
items: [],
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
groupItems(
|
|
225
|
+
_request: Billing.RecurringBillingItemHandling.GroupItemsInput,
|
|
226
|
+
_config: MyRecurringBillingItemHandlingConfig,
|
|
227
|
+
_context: Context
|
|
228
|
+
) {
|
|
229
|
+
// TODO: implement your group-items logic here
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
groups: [],
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
path: "extensions/common/.prettierignore",
|
|
240
|
+
content: `dist
|
|
241
|
+
generated
|
|
242
|
+
node_modules
|
|
243
|
+
`
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
path: "extensions/common/eslint.config.mts.mustache",
|
|
247
|
+
content: `import eslint from '@eslint/js';
|
|
248
|
+
import { defineConfig } from 'eslint/config';
|
|
249
|
+
import tseslint from 'typescript-eslint';
|
|
250
|
+
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
|
251
|
+
|
|
252
|
+
import globals from 'globals';
|
|
253
|
+
|
|
254
|
+
import stripeAppsConfig from '@stripe/extensibility-eslint-plugin';
|
|
255
|
+
import extensionTypeConfig from '@stripe/extensibility-eslint-plugin/{{extensionInterfaceId}}';
|
|
256
|
+
|
|
257
|
+
export default defineConfig([
|
|
258
|
+
eslint.configs.recommended,
|
|
259
|
+
...tseslint.configs.recommended,
|
|
260
|
+
...stripeAppsConfig,
|
|
261
|
+
...extensionTypeConfig,
|
|
262
|
+
|
|
263
|
+
// Global ignores
|
|
264
|
+
{
|
|
265
|
+
ignores: ['dist', 'generated', 'node_modules'],
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
// TypeScript source files (with type-checking)
|
|
269
|
+
{
|
|
270
|
+
name: 'sources',
|
|
271
|
+
files: ['src/**/*.ts'],
|
|
272
|
+
ignores: ['**/*.test.ts', '**/__tests__/**'],
|
|
273
|
+
languageOptions: {
|
|
274
|
+
globals: {
|
|
275
|
+
...globals.node,
|
|
276
|
+
},
|
|
277
|
+
parserOptions: {
|
|
278
|
+
projectService: true,
|
|
279
|
+
tsconfigRootDir: import.meta.dirname,
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
// Test files (type-checking, relaxed rules)
|
|
285
|
+
{
|
|
286
|
+
name: 'tests',
|
|
287
|
+
files: ['src/**/*.test.ts', 'src/**/__tests__/**/*.ts'],
|
|
288
|
+
languageOptions: {
|
|
289
|
+
globals: {
|
|
290
|
+
...globals.node,
|
|
291
|
+
},
|
|
292
|
+
parserOptions: {
|
|
293
|
+
projectService: true,
|
|
294
|
+
tsconfigRootDir: import.meta.dirname,
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
rules: {
|
|
298
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
299
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
300
|
+
'no-console': 'off',
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
// Config files
|
|
305
|
+
{
|
|
306
|
+
name: 'ts-configs',
|
|
307
|
+
files: ['*.config.m?ts', 'eslint.config.mts'],
|
|
308
|
+
languageOptions: {
|
|
309
|
+
globals: {
|
|
310
|
+
...globals.node,
|
|
311
|
+
},
|
|
312
|
+
parserOptions: {
|
|
313
|
+
projectService: false,
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
rules: {
|
|
317
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
// JavaScript/MJS files (scripts, configs)
|
|
322
|
+
{
|
|
323
|
+
name: 'js-configs',
|
|
324
|
+
files: ['**/*.js', '**/*.mjs'],
|
|
325
|
+
languageOptions: {
|
|
326
|
+
globals: {
|
|
327
|
+
...globals.node,
|
|
328
|
+
},
|
|
329
|
+
parserOptions: {
|
|
330
|
+
projectService: false,
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
rules: {
|
|
334
|
+
'@typescript-eslint/no-require-imports': 'off',
|
|
335
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
336
|
+
'no-unused-vars': 'off',
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
eslintConfigPrettier,
|
|
341
|
+
]);
|
|
342
|
+
`
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
path: "extensions/common/package.json.mustache",
|
|
346
|
+
content: `{
|
|
347
|
+
"name": "{{id}}",
|
|
348
|
+
"version": "{{version}}",
|
|
349
|
+
"description": "{{name}}",
|
|
350
|
+
"private": true,
|
|
351
|
+
"license": "~~proprietary~~",
|
|
352
|
+
"type": "module",
|
|
353
|
+
"scripts": {
|
|
354
|
+
"build": "tsc -p tsconfig.build.json && pnpm build:schemas",
|
|
355
|
+
"build:schemas": "gen-schemas --root ../.. --extension-id \\"$npm_package_name\\" --out-dir generated --schema-name config",
|
|
356
|
+
"lint": "pnpm lint:types && pnpm lint:eslint && pnpm lint:format",
|
|
357
|
+
"lint:types": "tsc -p tsconfig.build.json --noEmit && tsc -p tsconfig.json --noEmit",
|
|
358
|
+
"lint:eslint": "eslint .",
|
|
359
|
+
"lint:format": "prettier --check .",
|
|
360
|
+
"fix:lint": "eslint --fix .",
|
|
361
|
+
"fix:format": "prettier --write .",
|
|
362
|
+
"test": "vitest --root ../.. run --project \\"$npm_package_name\\"",
|
|
363
|
+
"test:watch": "pnpm test --watch",
|
|
364
|
+
"dev": "concurrently -n build,lint,test -c blue,yellow,green 'tsc -p tsconfig.json -w --noEmit' 'chokidar \\"src/**/*.{ts,json}\\" -c \\"eslint .\\"' 'pnpm test --watch --no-clear-screen'",
|
|
365
|
+
"stripe:regen": "gen-workspace --root ../.. --package-dir . --template-id {{extensionInterfaceId}}"
|
|
366
|
+
},
|
|
367
|
+
"lint-staged": {
|
|
368
|
+
"*.{ts,mts,mjs,js}": ["eslint --fix", "prettier --write"],
|
|
369
|
+
"*.{json,md,yaml}": "prettier --write"
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
`
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
path: "extensions/common/tsconfig.build.json.mustache",
|
|
376
|
+
content: `{
|
|
377
|
+
"extends": "../../tsconfig.base.json",
|
|
378
|
+
"compilerOptions": {
|
|
379
|
+
"lib": null,
|
|
380
|
+
"noLib": true,
|
|
381
|
+
"outDir": "./dist",
|
|
382
|
+
"rootDir": "./src"
|
|
383
|
+
},
|
|
384
|
+
"include": [
|
|
385
|
+
"src/**/*.ts",
|
|
386
|
+
"node_modules/@stripe/extensibility-sdk/tslibs/5.9.3/lib.es2022.{{executionProfile}}.d.ts",
|
|
387
|
+
"node_modules/@stripe/extensibility-sdk/tslibs/lib.{{executionProfile}}.globals.d.ts"
|
|
388
|
+
],
|
|
389
|
+
"exclude": ["src/**/*.test.ts", "src/**/__tests__"]
|
|
390
|
+
}
|
|
391
|
+
`
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
path: "extensions/common/tsconfig.json.mustache",
|
|
395
|
+
content: `{
|
|
396
|
+
"extends": "../../tsconfig.json",
|
|
397
|
+
"compilerOptions": {
|
|
398
|
+
"rootDir": ".",
|
|
399
|
+
"plugins": [
|
|
400
|
+
{
|
|
401
|
+
"name": "@stripe/extensibility-language-server/plugin"
|
|
402
|
+
}
|
|
403
|
+
]
|
|
404
|
+
},
|
|
405
|
+
"include": [
|
|
406
|
+
"src/**/*.ts",
|
|
407
|
+
"node_modules/@stripe/extensibility-sdk/tslibs/lib.{{executionProfile}}.globals.d.ts"
|
|
408
|
+
],
|
|
409
|
+
"exclude": ["dist"]
|
|
410
|
+
}
|
|
411
|
+
`
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
path: "extensions/core.workflows.custom_action/custom_input.schema.json",
|
|
415
|
+
content: `{
|
|
416
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
417
|
+
"type": "object",
|
|
418
|
+
"properties": {},
|
|
419
|
+
"additionalProperties": false
|
|
420
|
+
}
|
|
421
|
+
`
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
path: "extensions/core.workflows.custom_action/index.test.ts",
|
|
425
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
426
|
+
|
|
427
|
+
import MyCustomAction from './index.js';
|
|
428
|
+
|
|
429
|
+
describe('MyCustomAction', () => {
|
|
430
|
+
let instance: MyCustomAction;
|
|
431
|
+
|
|
432
|
+
beforeEach(() => {
|
|
433
|
+
instance = new MyCustomAction();
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should be constructable', () => {
|
|
437
|
+
expect(instance).toBeInstanceOf(MyCustomAction);
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
`
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
path: "extensions/core.workflows.custom_action/index.ts",
|
|
444
|
+
content: `import type { Core } from '@stripe/extensibility-sdk/extensions';
|
|
445
|
+
import type { Context } from '@stripe/extensibility-sdk/extensions';
|
|
446
|
+
|
|
447
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
448
|
+
interface MyCustomActionConfig extends Record<string, unknown> {}
|
|
449
|
+
|
|
450
|
+
export default class MyCustomAction implements Core.Workflows
|
|
451
|
+
.CustomAction<MyCustomActionConfig> {
|
|
452
|
+
execute(
|
|
453
|
+
_request: Core.Workflows.CustomAction.ExecuteCustomActionRequest,
|
|
454
|
+
_config: MyCustomActionConfig,
|
|
455
|
+
_context: Context
|
|
456
|
+
) {
|
|
457
|
+
// TODO: implement your action logic here
|
|
458
|
+
|
|
459
|
+
return {};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
getFormState(
|
|
463
|
+
_request: Core.Workflows.CustomAction.GetFormStateRequest,
|
|
464
|
+
_config: MyCustomActionConfig,
|
|
465
|
+
_context: Context
|
|
466
|
+
) {
|
|
467
|
+
// TODO: implement your logic here
|
|
468
|
+
|
|
469
|
+
return {
|
|
470
|
+
values: {},
|
|
471
|
+
config: {},
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
`
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
path: "extensions/extend.workflows.custom_action/custom_input.schema.json",
|
|
479
|
+
content: `{
|
|
480
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
481
|
+
"type": "object",
|
|
482
|
+
"properties": {},
|
|
483
|
+
"additionalProperties": false
|
|
484
|
+
}
|
|
485
|
+
`
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
path: "extensions/extend.workflows.custom_action/index.test.ts",
|
|
489
|
+
content: `import { beforeEach, describe, it, expect } from 'vitest';
|
|
490
|
+
|
|
491
|
+
import MyCustomAction from './index.js';
|
|
492
|
+
|
|
493
|
+
describe('MyCustomAction', () => {
|
|
494
|
+
let instance: MyCustomAction;
|
|
495
|
+
|
|
496
|
+
beforeEach(() => {
|
|
497
|
+
instance = new MyCustomAction();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('should be constructable', () => {
|
|
501
|
+
expect(instance).toBeInstanceOf(MyCustomAction);
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
`
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
path: "extensions/extend.workflows.custom_action/index.ts",
|
|
508
|
+
content: `import type { Extend } from '@stripe/extensibility-sdk/extensions';
|
|
509
|
+
import type { Context } from '@stripe/extensibility-sdk/extensions';
|
|
510
|
+
|
|
511
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
512
|
+
interface MyCustomActionConfig extends Record<string, unknown> {}
|
|
513
|
+
|
|
514
|
+
export default class MyCustomAction implements Extend.Workflows
|
|
515
|
+
.CustomAction<MyCustomActionConfig> {
|
|
516
|
+
execute(
|
|
517
|
+
_request: Extend.Workflows.CustomAction.ExecuteCustomActionRequest,
|
|
518
|
+
_config: MyCustomActionConfig,
|
|
519
|
+
_context: Context
|
|
520
|
+
) {
|
|
521
|
+
// TODO: implement your action logic here
|
|
522
|
+
|
|
523
|
+
return {};
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
getFormState(
|
|
527
|
+
_request: Extend.Workflows.CustomAction.GetFormStateRequest,
|
|
528
|
+
_config: MyCustomActionConfig,
|
|
529
|
+
_context: Context
|
|
530
|
+
) {
|
|
531
|
+
// TODO: implement your logic here
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
values: {},
|
|
535
|
+
config: {},
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
`
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
path: "root/.husky/pre-commit",
|
|
543
|
+
content: `pnpm lint-staged
|
|
544
|
+
`
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
path: "root/.prettierignore",
|
|
548
|
+
content: `dist
|
|
549
|
+
generated
|
|
550
|
+
node_modules
|
|
551
|
+
pnpm-lock.yaml
|
|
552
|
+
.build
|
|
553
|
+
`
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
path: "root/.prettierrc",
|
|
557
|
+
content: `{
|
|
558
|
+
"semi": true,
|
|
559
|
+
"singleQuote": true,
|
|
560
|
+
"tabWidth": 2,
|
|
561
|
+
"trailingComma": "es5",
|
|
562
|
+
"printWidth": 90
|
|
563
|
+
}
|
|
564
|
+
`
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
path: "root/_gitignore",
|
|
568
|
+
content: `# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
569
|
+
|
|
570
|
+
*~
|
|
571
|
+
|
|
572
|
+
# dependencies
|
|
573
|
+
node_modules
|
|
574
|
+
dist
|
|
575
|
+
|
|
576
|
+
# testing
|
|
577
|
+
/coverage
|
|
578
|
+
|
|
579
|
+
# production
|
|
580
|
+
/.build
|
|
581
|
+
|
|
582
|
+
# misc
|
|
583
|
+
.DS_Store
|
|
584
|
+
.env.local
|
|
585
|
+
.env.development.local
|
|
586
|
+
.env.test.local
|
|
587
|
+
.env.production.local
|
|
588
|
+
|
|
589
|
+
npm-debug.log*
|
|
590
|
+
yarn-debug.log*
|
|
591
|
+
yarn-error.log*
|
|
592
|
+
install-deps.log
|
|
593
|
+
|
|
594
|
+
# generated schemas
|
|
595
|
+
generated
|
|
596
|
+
`
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
path: "root/custom-objects/package.json",
|
|
600
|
+
content: `{
|
|
601
|
+
"name": "custom-objects",
|
|
602
|
+
"type": "module",
|
|
603
|
+
"version": "0.0.1",
|
|
604
|
+
"license": "UNLICENSED",
|
|
605
|
+
"private": true,
|
|
606
|
+
"scripts": {
|
|
607
|
+
"build": "test -d src && custom-objects-build --input src --output dist || true",
|
|
608
|
+
"lint:types": "test ! -d src || tsc --noEmit",
|
|
609
|
+
"test": "vitest run"
|
|
610
|
+
},
|
|
611
|
+
"dependencies": {
|
|
612
|
+
"@stripe/extensibility-custom-objects": "0.7.4",
|
|
613
|
+
"@stripe/extensibility-sdk": "0.22.4"
|
|
614
|
+
},
|
|
615
|
+
"devDependencies": {
|
|
616
|
+
"@stripe/extensibility-custom-objects-tools": "0.40.0",
|
|
617
|
+
"@stripe/extensibility-test-helpers": "0.2.7"
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
`
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
path: "root/custom-objects/tsconfig.json",
|
|
624
|
+
content: `{
|
|
625
|
+
"extends": "../tsconfig.base.json",
|
|
626
|
+
"compilerOptions": {
|
|
627
|
+
"module": "ESNext",
|
|
628
|
+
"moduleResolution": "bundler",
|
|
629
|
+
"types": ["vitest/globals"]
|
|
630
|
+
},
|
|
631
|
+
"exclude": ["dist"]
|
|
632
|
+
}
|
|
633
|
+
`
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
path: "root/eslint.config.mts",
|
|
637
|
+
content: `import { readFileSync } from 'node:fs';
|
|
638
|
+
import { dirname, resolve } from 'node:path';
|
|
639
|
+
import { fileURLToPath } from 'node:url';
|
|
640
|
+
import eslint from '@eslint/js';
|
|
641
|
+
import { defineConfig } from 'eslint/config';
|
|
642
|
+
import tseslint from 'typescript-eslint';
|
|
643
|
+
import workspaces from 'eslint-plugin-workspaces';
|
|
644
|
+
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
|
645
|
+
|
|
646
|
+
import globals from 'globals';
|
|
647
|
+
|
|
648
|
+
import stripeAppsConfig from '@stripe/extensibility-eslint-plugin';
|
|
649
|
+
|
|
650
|
+
// Read additional ignore globs from package.json (written by the generate plugin
|
|
651
|
+
// to exclude generated SDK directories from linting).
|
|
652
|
+
let stripeGlobsToIgnore: string[] = [];
|
|
653
|
+
try {
|
|
654
|
+
const configDir = dirname(fileURLToPath(import.meta.url));
|
|
655
|
+
const packageJsonPath = resolve(configDir, './package.json');
|
|
656
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
657
|
+
const globs = pkg?.stripe?.eslintIgnoreGlobs;
|
|
658
|
+
if (Array.isArray(globs)) {
|
|
659
|
+
stripeGlobsToIgnore = globs.filter(
|
|
660
|
+
(g: unknown): g is string => typeof g === 'string'
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
} catch {
|
|
664
|
+
// package.json not found or unparseable \u2014 ignore
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
export default defineConfig([
|
|
668
|
+
eslint.configs.recommended,
|
|
669
|
+
...tseslint.configs.recommended,
|
|
670
|
+
...stripeAppsConfig,
|
|
671
|
+
|
|
672
|
+
// Global ignores
|
|
673
|
+
{
|
|
674
|
+
ignores: [
|
|
675
|
+
'.build',
|
|
676
|
+
'**/dist',
|
|
677
|
+
'**/generated',
|
|
678
|
+
'**/node_modules',
|
|
679
|
+
'extensions/**',
|
|
680
|
+
'custom-objects',
|
|
681
|
+
'ui',
|
|
682
|
+
...stripeGlobsToIgnore,
|
|
683
|
+
],
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
// Common rules for all files
|
|
687
|
+
{
|
|
688
|
+
plugins: { workspaces },
|
|
689
|
+
rules: {
|
|
690
|
+
...workspaces.configs.recommended.rules,
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
|
|
694
|
+
// Config files (vitest.config.ts, eslint.config.ts, etc.)
|
|
695
|
+
{
|
|
696
|
+
name: 'ts-configs',
|
|
697
|
+
files: ['extensions/*/*.config.m?ts', '*.config.m?ts', 'eslint.config.mts'],
|
|
698
|
+
languageOptions: {
|
|
699
|
+
globals: {
|
|
700
|
+
...globals.node,
|
|
701
|
+
},
|
|
702
|
+
parserOptions: {
|
|
703
|
+
projectService: false,
|
|
704
|
+
},
|
|
705
|
+
},
|
|
706
|
+
rules: {
|
|
707
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
|
|
711
|
+
// JavaScript/MJS files (scripts, configs)
|
|
712
|
+
{
|
|
713
|
+
name: 'js-configs',
|
|
714
|
+
files: ['**/*.js', '**/*.mjs'],
|
|
715
|
+
languageOptions: {
|
|
716
|
+
globals: {
|
|
717
|
+
...globals.node,
|
|
718
|
+
},
|
|
719
|
+
parserOptions: {
|
|
720
|
+
projectService: false,
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
rules: {
|
|
724
|
+
'@typescript-eslint/no-require-imports': 'off',
|
|
725
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
726
|
+
'no-unused-vars': 'off',
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
eslintConfigPrettier,
|
|
731
|
+
]);
|
|
732
|
+
`
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
path: "root/package.json.mustache",
|
|
736
|
+
content: `{
|
|
737
|
+
"name": "{{ appId }}",
|
|
738
|
+
"version": "{{ version }}",
|
|
739
|
+
"description": "{{ appName }}",
|
|
740
|
+
"private": true,
|
|
741
|
+
"license": "~~proprietary~~",
|
|
742
|
+
"engines": {
|
|
743
|
+
"node": ">=20.0.0"
|
|
744
|
+
},
|
|
745
|
+
"packageManager": "pnpm@10.30.3",
|
|
746
|
+
"scripts": {
|
|
747
|
+
"build": "pnpm -r --if-present build",
|
|
748
|
+
"lint": "pnpm lint:types && pnpm lint:eslint && pnpm lint:format",
|
|
749
|
+
"lint:types": "pnpm -r --if-present lint:types",
|
|
750
|
+
"lint:eslint": "eslint . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present lint:eslint",
|
|
751
|
+
"lint:format": "prettier --check .",
|
|
752
|
+
"fix:lint": "eslint --fix . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present fix:lint",
|
|
753
|
+
"fix:format": "prettier --write .",
|
|
754
|
+
"test": "tsx tools/test.mts",
|
|
755
|
+
"test:watch": "vitest watch",
|
|
756
|
+
"check": "pnpm build && pnpm lint && pnpm test",
|
|
757
|
+
"prepare": "husky",
|
|
758
|
+
"preimage": "pnpm install --lockfile-only && pnpm build && pnpm lint:types && pnpm lint:eslint && pnpm test",
|
|
759
|
+
"image": "rm -rf .build && create-upload-image .build",
|
|
760
|
+
"postimage": "cp pnpm-lock.yaml .build/",
|
|
761
|
+
"stripe:regen": "gen-workspace --package-dir ."
|
|
762
|
+
},
|
|
763
|
+
"lint-staged": {
|
|
764
|
+
"*.{ts,mts,mjs,js}": ["eslint --fix", "prettier --write"],
|
|
765
|
+
"*.{json,md,yaml}": "prettier --write"
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
`
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
path: "root/pnpm-workspace.yaml",
|
|
772
|
+
content: `packages:
|
|
773
|
+
- extensions/*
|
|
774
|
+
- custom-objects
|
|
775
|
+
- ui
|
|
776
|
+
|
|
777
|
+
overrides:
|
|
778
|
+
vite: ^6.0.0
|
|
779
|
+
`
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
path: "root/stripe-app.yaml.mustache",
|
|
783
|
+
content: `$schema: https://stripe.com/stripe-app/v2.0.0/schema
|
|
784
|
+
id: '{{ appId }}'
|
|
785
|
+
name: '{{ appName }}'
|
|
786
|
+
version: 0.0.1
|
|
787
|
+
declarations:
|
|
788
|
+
distribution_type: private
|
|
789
|
+
`
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
path: "root/tools/test.mts",
|
|
793
|
+
content: `#!/usr/bin/env tsx
|
|
794
|
+
/**
|
|
795
|
+
* Runs tests across the workspace:
|
|
796
|
+
* - vitest for script extensions and custom objects (extensions/*)
|
|
797
|
+
* - jest for UI extensions (ui/)
|
|
798
|
+
*/
|
|
799
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
800
|
+
import { execSync } from 'node:child_process';
|
|
801
|
+
|
|
802
|
+
const hasExtensions =
|
|
803
|
+
existsSync('extensions') &&
|
|
804
|
+
readdirSync('extensions').some((name) => existsSync(\`extensions/\${name}/package.json\`));
|
|
805
|
+
|
|
806
|
+
const hasUI = existsSync('ui/package.json');
|
|
807
|
+
|
|
808
|
+
let exitCode = 0;
|
|
809
|
+
|
|
810
|
+
function run(cmd: string): void {
|
|
811
|
+
try {
|
|
812
|
+
execSync(cmd, { stdio: 'inherit' });
|
|
813
|
+
} catch (e: unknown) {
|
|
814
|
+
exitCode = (e as NodeJS.ErrnoException & { status?: number }).status ?? 1;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (hasExtensions) {
|
|
819
|
+
run('vitest run');
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (hasUI) {
|
|
823
|
+
try {
|
|
824
|
+
execSync('pnpm --filter "./ui" test', { stdio: 'inherit' });
|
|
825
|
+
} catch {
|
|
826
|
+
// UI test failures are non-fatal
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
process.exit(exitCode);
|
|
831
|
+
`
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
path: "root/tsconfig.base.json",
|
|
835
|
+
content: `{
|
|
836
|
+
"compilerOptions": {
|
|
837
|
+
"target": "ES2022",
|
|
838
|
+
"module": "NodeNext",
|
|
839
|
+
"moduleResolution": "NodeNext",
|
|
840
|
+
"lib": ["ES2022"],
|
|
841
|
+
"declaration": true,
|
|
842
|
+
"declarationMap": true,
|
|
843
|
+
"esModuleInterop": true,
|
|
844
|
+
"exactOptionalPropertyTypes": false,
|
|
845
|
+
"forceConsistentCasingInFileNames": true,
|
|
846
|
+
"isolatedModules": true,
|
|
847
|
+
"noFallthroughCasesInSwitch": true,
|
|
848
|
+
"noImplicitReturns": true,
|
|
849
|
+
"removeComments": false,
|
|
850
|
+
"resolveJsonModule": true,
|
|
851
|
+
"skipLibCheck": true,
|
|
852
|
+
"sourceMap": true,
|
|
853
|
+
"strict": true,
|
|
854
|
+
"types": [],
|
|
855
|
+
"verbatimModuleSyntax": true
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
`
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
path: "root/tsconfig.json",
|
|
862
|
+
content: `{
|
|
863
|
+
"extends": "./tsconfig.base.json",
|
|
864
|
+
"compilerOptions": {
|
|
865
|
+
"noEmit": true,
|
|
866
|
+
"plugins": [
|
|
867
|
+
{
|
|
868
|
+
"name": "@stripe/extensibility-language-server/plugin"
|
|
869
|
+
}
|
|
870
|
+
],
|
|
871
|
+
"preserveWatchOutput": true,
|
|
872
|
+
"types": ["vitest/globals", "node"]
|
|
873
|
+
},
|
|
874
|
+
"include": ["**/*.ts"],
|
|
875
|
+
"exclude": ["**/node_modules", "**/dist"]
|
|
876
|
+
}
|
|
877
|
+
`
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
path: "root/ui/package.json",
|
|
881
|
+
content: `{
|
|
882
|
+
"name": "ui",
|
|
883
|
+
"version": "0.0.1",
|
|
884
|
+
"license": "UNLICENSED",
|
|
885
|
+
"private": true,
|
|
886
|
+
"scripts": {
|
|
887
|
+
"test": "jest --passWithNoTests"
|
|
888
|
+
},
|
|
889
|
+
"dependencies": {
|
|
890
|
+
"@stripe/ui-extension-sdk": "^9.1.0"
|
|
891
|
+
},
|
|
892
|
+
"devDependencies": {
|
|
893
|
+
"@stripe/ui-extension-tools": "^0.0.1",
|
|
894
|
+
"@types/jest": "^27.5.2",
|
|
895
|
+
"@types/react": "^17.0.2"
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
`
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
path: "root/vitest.config.mts",
|
|
902
|
+
content: `import { defineConfig } from 'vitest/config';
|
|
903
|
+
import { existsSync, readdirSync } from 'fs';
|
|
904
|
+
import { dirname, resolve } from 'path';
|
|
905
|
+
import { fileURLToPath } from 'url';
|
|
906
|
+
|
|
907
|
+
const rootDir = dirname(fileURLToPath(import.meta.url));
|
|
908
|
+
const extensionsDir = resolve(rootDir, 'extensions');
|
|
909
|
+
|
|
910
|
+
const extensionProjects = existsSync(extensionsDir)
|
|
911
|
+
? readdirSync(extensionsDir)
|
|
912
|
+
.filter((name) => existsSync(resolve(extensionsDir, name, 'package.json')))
|
|
913
|
+
.map((name) => resolve(extensionsDir, name))
|
|
914
|
+
: [];
|
|
915
|
+
|
|
916
|
+
const coProjects = existsSync(resolve(rootDir, 'custom-objects/package.json'))
|
|
917
|
+
? [resolve(rootDir, 'custom-objects')]
|
|
918
|
+
: [];
|
|
919
|
+
|
|
920
|
+
const projects = [...extensionProjects, ...coProjects];
|
|
921
|
+
|
|
922
|
+
if (projects.length === 0) {
|
|
923
|
+
console.debug(\`No vitest projects detected. This means either:
|
|
924
|
+
- You have no extension projects defined, in which case this warning is expected.
|
|
925
|
+
- There is an internal error detecting vitest projects relative to the project root
|
|
926
|
+
\${rootDir}.
|
|
927
|
+
\`);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
export default projects.length > 0
|
|
931
|
+
? defineConfig({
|
|
932
|
+
test: {
|
|
933
|
+
projects,
|
|
934
|
+
passWithNoTests: true,
|
|
935
|
+
|
|
936
|
+
// Only run tests from src, not compiled dist
|
|
937
|
+
exclude: ['**/node_modules', '**/dist'],
|
|
938
|
+
// Place snapshots alongside test files instead of in __snapshots__
|
|
939
|
+
snapshotFormat: {
|
|
940
|
+
escapeString: false,
|
|
941
|
+
printBasicPrototype: false,
|
|
942
|
+
},
|
|
943
|
+
resolveSnapshotPath: (testPath, snapExtension) => {
|
|
944
|
+
return testPath.replace(/\\.test\\.ts$/, \`.test\${snapExtension}\`);
|
|
945
|
+
},
|
|
946
|
+
},
|
|
947
|
+
})
|
|
948
|
+
: defineConfig({ test: { passWithNoTests: true, include: [] } });
|
|
949
|
+
`
|
|
950
|
+
}
|
|
951
|
+
];
|
|
952
|
+
var _fs = _createInMemoryTemplateFS(TEMPLATE_FS_IMAGE);
|
|
953
|
+
|
|
954
|
+
// src/templates/simple-templates.ts
|
|
955
|
+
import {
|
|
956
|
+
_createSimpleTemplate,
|
|
957
|
+
_SingleTemplateManager,
|
|
958
|
+
_createSimpleSingleFileTemplate
|
|
959
|
+
} from "@stripe/extensibility-tool-utils";
|
|
960
|
+
|
|
961
|
+
// src/templates/file-writer.ts
|
|
962
|
+
import path from "path";
|
|
963
|
+
import { mkdir, writeFile, readFile } from "fs/promises";
|
|
964
|
+
import { createInterface } from "readline";
|
|
965
|
+
import { _createLogger } from "@stripe/extensibility-tool-utils";
|
|
966
|
+
|
|
967
|
+
// src/templates/fs-utils.ts
|
|
968
|
+
import { stat } from "fs/promises";
|
|
969
|
+
async function pathExists(filePath, predicate) {
|
|
970
|
+
try {
|
|
971
|
+
const stats = await stat(filePath);
|
|
972
|
+
return predicate(stats);
|
|
973
|
+
} catch (error) {
|
|
974
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
throw error;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
async function fileExists(filePath) {
|
|
981
|
+
return pathExists(filePath, (stats) => stats.isFile());
|
|
982
|
+
}
|
|
983
|
+
async function directoryExists(dirPath) {
|
|
984
|
+
return pathExists(dirPath, (stats) => stats.isDirectory());
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/templates/file-writer.ts
|
|
988
|
+
var logger = _createLogger({ name: "file-writer" });
|
|
989
|
+
async function _promptOverwrite(filePath) {
|
|
990
|
+
const prompt = `${filePath} exists. Overwrite [yNaq]? `;
|
|
991
|
+
if (!process.stdin.isTTY) {
|
|
992
|
+
const rl = createInterface({
|
|
993
|
+
input: process.stdin,
|
|
994
|
+
output: process.stdout
|
|
995
|
+
});
|
|
996
|
+
return new Promise((resolve) => {
|
|
997
|
+
rl.question(prompt, (answer) => {
|
|
998
|
+
rl.close();
|
|
999
|
+
const normalized = answer.toLowerCase().trim();
|
|
1000
|
+
switch (normalized) {
|
|
1001
|
+
case "y":
|
|
1002
|
+
case "yes":
|
|
1003
|
+
resolve("overwrite");
|
|
1004
|
+
break;
|
|
1005
|
+
case "n":
|
|
1006
|
+
case "no":
|
|
1007
|
+
case "":
|
|
1008
|
+
resolve("skip");
|
|
1009
|
+
break;
|
|
1010
|
+
case "a":
|
|
1011
|
+
case "all":
|
|
1012
|
+
resolve("overwrite-all");
|
|
1013
|
+
break;
|
|
1014
|
+
case "q":
|
|
1015
|
+
case "quit":
|
|
1016
|
+
resolve("abort");
|
|
1017
|
+
break;
|
|
1018
|
+
default:
|
|
1019
|
+
logger.warn("Invalid input '%s', treating as 'no'", answer);
|
|
1020
|
+
resolve("skip");
|
|
1021
|
+
}
|
|
1022
|
+
});
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
process.stdout.write(prompt);
|
|
1026
|
+
return new Promise((resolve) => {
|
|
1027
|
+
const stdin = process.stdin;
|
|
1028
|
+
const wasRaw = stdin.isRaw;
|
|
1029
|
+
stdin.setRawMode(true);
|
|
1030
|
+
stdin.resume();
|
|
1031
|
+
const onData = (buffer) => {
|
|
1032
|
+
stdin.setRawMode(wasRaw || false);
|
|
1033
|
+
stdin.pause();
|
|
1034
|
+
stdin.removeListener("data", onData);
|
|
1035
|
+
const key = buffer.toString();
|
|
1036
|
+
const code = buffer[0];
|
|
1037
|
+
if (code === 3) {
|
|
1038
|
+
process.stdout.write("\nCancelled.\n");
|
|
1039
|
+
setTimeout(() => process.exit(0), 100);
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
if (code === 13 || code === 10) {
|
|
1043
|
+
process.stdout.write("n\n");
|
|
1044
|
+
resolve("skip");
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
const normalized = key.toLowerCase();
|
|
1048
|
+
let decision;
|
|
1049
|
+
switch (normalized) {
|
|
1050
|
+
case "y":
|
|
1051
|
+
process.stdout.write("y\n");
|
|
1052
|
+
decision = "overwrite";
|
|
1053
|
+
break;
|
|
1054
|
+
case "n":
|
|
1055
|
+
process.stdout.write("n\n");
|
|
1056
|
+
decision = "skip";
|
|
1057
|
+
break;
|
|
1058
|
+
case "a":
|
|
1059
|
+
process.stdout.write("a\n");
|
|
1060
|
+
decision = "overwrite-all";
|
|
1061
|
+
break;
|
|
1062
|
+
case "q":
|
|
1063
|
+
process.stdout.write("q\n");
|
|
1064
|
+
decision = "abort";
|
|
1065
|
+
break;
|
|
1066
|
+
default:
|
|
1067
|
+
process.stdout.write(`${key}
|
|
1068
|
+
`);
|
|
1069
|
+
logger.warn("Invalid input '%s', treating as 'no'", key);
|
|
1070
|
+
decision = "skip";
|
|
1071
|
+
}
|
|
1072
|
+
resolve(decision);
|
|
1073
|
+
};
|
|
1074
|
+
stdin.on("data", onData);
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
async function _writeGeneratedFiles(files, options = {}) {
|
|
1078
|
+
const { cwd = process.cwd(), onFileWritten, onFileSkipped, onFileIdentical } = options;
|
|
1079
|
+
let write = options.write ?? "abort-if-existing";
|
|
1080
|
+
const existing = [];
|
|
1081
|
+
for (const file of files) {
|
|
1082
|
+
const fullPath = path.join(cwd, file.path);
|
|
1083
|
+
if (await fileExists(fullPath)) {
|
|
1084
|
+
existing.push(file.path);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
if (existing.length > 0 && write === "abort-if-existing") {
|
|
1088
|
+
if (onFileSkipped) {
|
|
1089
|
+
for (const file of files) {
|
|
1090
|
+
if (existing.includes(file.path)) {
|
|
1091
|
+
onFileSkipped(file);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
written: [],
|
|
1097
|
+
existing,
|
|
1098
|
+
skipped: true,
|
|
1099
|
+
aborted: false
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
const written = [];
|
|
1103
|
+
for (const file of files) {
|
|
1104
|
+
const fullPath = path.join(cwd, file.path);
|
|
1105
|
+
const fileDir = path.dirname(fullPath);
|
|
1106
|
+
const isExisting = existing.includes(file.path);
|
|
1107
|
+
if (isExisting) {
|
|
1108
|
+
const existingContent = await readFile(fullPath, "utf-8");
|
|
1109
|
+
if (existingContent === file.content) {
|
|
1110
|
+
if (onFileIdentical) {
|
|
1111
|
+
onFileIdentical(file);
|
|
1112
|
+
}
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
if (isExisting && (write === "if-missing" || file.precious)) {
|
|
1117
|
+
if (onFileSkipped) {
|
|
1118
|
+
onFileSkipped(file);
|
|
1119
|
+
}
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
if (isExisting && typeof write === "function") {
|
|
1123
|
+
const decision = await write(file.path, cwd, file.content);
|
|
1124
|
+
switch (decision) {
|
|
1125
|
+
case "skip":
|
|
1126
|
+
if (onFileSkipped) {
|
|
1127
|
+
onFileSkipped(file);
|
|
1128
|
+
}
|
|
1129
|
+
continue;
|
|
1130
|
+
case "overwrite":
|
|
1131
|
+
break;
|
|
1132
|
+
case "overwrite-all":
|
|
1133
|
+
write = "overwrite-all";
|
|
1134
|
+
break;
|
|
1135
|
+
case "abort":
|
|
1136
|
+
return {
|
|
1137
|
+
written,
|
|
1138
|
+
existing,
|
|
1139
|
+
skipped: false,
|
|
1140
|
+
aborted: true
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (!await directoryExists(fileDir)) {
|
|
1145
|
+
await mkdir(fileDir, { recursive: true });
|
|
1146
|
+
}
|
|
1147
|
+
await writeFile(fullPath, file.content, "utf-8");
|
|
1148
|
+
if (onFileWritten) {
|
|
1149
|
+
onFileWritten(file, isExisting);
|
|
1150
|
+
}
|
|
1151
|
+
written.push(file.path);
|
|
1152
|
+
}
|
|
1153
|
+
return {
|
|
1154
|
+
written,
|
|
1155
|
+
existing,
|
|
1156
|
+
// Always populated; write='abort-if-existing' returns early above
|
|
1157
|
+
skipped: false,
|
|
1158
|
+
aborted: false
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// src/templates/diff-viewer/diff-prompt.ts
|
|
1163
|
+
import path2 from "path";
|
|
1164
|
+
|
|
1165
|
+
// src/templates/diff-viewer/diff-generator.ts
|
|
1166
|
+
import { createPatch } from "diff";
|
|
1167
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
1168
|
+
async function generateDiff(filePath, oldContent, newContent, contextLines = 3) {
|
|
1169
|
+
if (isBinary(oldContent) || isBinary(newContent)) {
|
|
1170
|
+
return {
|
|
1171
|
+
lines: [{ type: "header", text: "Binary file changed" }],
|
|
1172
|
+
oldFileName: filePath,
|
|
1173
|
+
newFileName: filePath,
|
|
1174
|
+
isBinary: true
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
const patch = createPatch(filePath, oldContent, newContent, "existing", "new", {
|
|
1178
|
+
context: contextLines
|
|
1179
|
+
});
|
|
1180
|
+
const lines = parsePatch(patch);
|
|
1181
|
+
return {
|
|
1182
|
+
lines,
|
|
1183
|
+
oldFileName: filePath,
|
|
1184
|
+
newFileName: filePath,
|
|
1185
|
+
isBinary: false
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
function parsePatch(patch) {
|
|
1189
|
+
const lines = [];
|
|
1190
|
+
const patchLines = patch.split("\n");
|
|
1191
|
+
let oldLine = 0;
|
|
1192
|
+
let newLine = 0;
|
|
1193
|
+
for (const line of patchLines) {
|
|
1194
|
+
if (line.startsWith("@@")) {
|
|
1195
|
+
const match = line.match(/@@ -(\d+),?\d* \+(\d+),?\d* @@/);
|
|
1196
|
+
if (match !== null) {
|
|
1197
|
+
oldLine = parseInt(match[1], 10);
|
|
1198
|
+
newLine = parseInt(match[2], 10);
|
|
1199
|
+
lines.push({ type: "header", text: line });
|
|
1200
|
+
}
|
|
1201
|
+
} else if (line.startsWith("+")) {
|
|
1202
|
+
lines.push({ type: "add", text: line, newLine: newLine++ });
|
|
1203
|
+
} else if (line.startsWith("-")) {
|
|
1204
|
+
lines.push({ type: "remove", text: line, oldLine: oldLine++ });
|
|
1205
|
+
} else if (line.startsWith(" ")) {
|
|
1206
|
+
lines.push({
|
|
1207
|
+
type: "context",
|
|
1208
|
+
text: line,
|
|
1209
|
+
oldLine: oldLine++,
|
|
1210
|
+
newLine: newLine++
|
|
1211
|
+
});
|
|
1212
|
+
} else if (line.startsWith("\\")) {
|
|
1213
|
+
lines.push({ type: "context", text: line });
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return lines;
|
|
1217
|
+
}
|
|
1218
|
+
function isBinary(content) {
|
|
1219
|
+
return content.includes("\0");
|
|
1220
|
+
}
|
|
1221
|
+
async function readExistingFile(resolvedPath) {
|
|
1222
|
+
try {
|
|
1223
|
+
return await readFile2(resolvedPath, "utf-8");
|
|
1224
|
+
} catch (err) {
|
|
1225
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
1226
|
+
return "";
|
|
1227
|
+
}
|
|
1228
|
+
throw err;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// src/templates/diff-viewer/terminal-renderer.ts
|
|
1233
|
+
import { execSync } from "child_process";
|
|
1234
|
+
import stringWidth from "string-width";
|
|
1235
|
+
var ANSI = {
|
|
1236
|
+
// Colors
|
|
1237
|
+
RED: "\x1B[31m",
|
|
1238
|
+
GREEN: "\x1B[32m",
|
|
1239
|
+
CYAN: "\x1B[36m",
|
|
1240
|
+
GRAY: "\x1B[90m",
|
|
1241
|
+
RESET: "\x1B[0m",
|
|
1242
|
+
// Text styles
|
|
1243
|
+
BOLD: "\x1B[1m",
|
|
1244
|
+
DIM: "\x1B[2m"
|
|
1245
|
+
};
|
|
1246
|
+
var BOX_HORIZONTAL = "\u2500";
|
|
1247
|
+
function render(state, filePath, clearPrevious = false) {
|
|
1248
|
+
const maxTotalHeight = Math.floor(state.terminalHeight * 0.75);
|
|
1249
|
+
const maxContentHeight = maxTotalHeight - 3;
|
|
1250
|
+
const contentHeight = state.diffLines.length;
|
|
1251
|
+
const windowHeight = Math.min(contentHeight, maxContentHeight);
|
|
1252
|
+
const visibleLines = state.diffLines.slice(
|
|
1253
|
+
state.scrollOffset,
|
|
1254
|
+
state.scrollOffset + windowHeight
|
|
1255
|
+
);
|
|
1256
|
+
const totalLines = state.diffLines.length;
|
|
1257
|
+
const startLine = state.scrollOffset + 1;
|
|
1258
|
+
const endLine = state.scrollOffset + visibleLines.length;
|
|
1259
|
+
if (clearPrevious && state.renderedHeight > 0) {
|
|
1260
|
+
clearPreviousRender(state.renderedHeight - 1);
|
|
1261
|
+
}
|
|
1262
|
+
let output = "";
|
|
1263
|
+
output += renderTopBar(filePath, state.terminalWidth) + "\n";
|
|
1264
|
+
for (const line of visibleLines) {
|
|
1265
|
+
output += colorize(line, state.terminalWidth) + "\n";
|
|
1266
|
+
}
|
|
1267
|
+
output += renderBottomBar(startLine, endLine, totalLines, state, state.terminalWidth) + "\n";
|
|
1268
|
+
output += "\n";
|
|
1269
|
+
output += `overwrite ${filePath} [yNaqd]? `;
|
|
1270
|
+
state.renderedHeight = 1 + visibleLines.length + 1 + 1 + 1;
|
|
1271
|
+
process.stdout.write(output);
|
|
1272
|
+
}
|
|
1273
|
+
function clearPreviousRender(lines) {
|
|
1274
|
+
process.stdout.write(`\x1B[${lines}A`);
|
|
1275
|
+
process.stdout.write("\r");
|
|
1276
|
+
process.stdout.write("\x1B[0J");
|
|
1277
|
+
}
|
|
1278
|
+
function renderTopBar(filePath, width) {
|
|
1279
|
+
const prefix = BOX_HORIZONTAL.repeat(3) + " ";
|
|
1280
|
+
const suffix = " " + BOX_HORIZONTAL.repeat(3);
|
|
1281
|
+
const availableWidth = width - stringWidth(prefix) - stringWidth(suffix);
|
|
1282
|
+
let displayName = filePath;
|
|
1283
|
+
if (stringWidth(displayName) + 1 > availableWidth) {
|
|
1284
|
+
while (stringWidth("..." + displayName) + 1 > availableWidth && displayName.length > 0) {
|
|
1285
|
+
displayName = displayName.slice(1);
|
|
1286
|
+
}
|
|
1287
|
+
displayName = "..." + displayName;
|
|
1288
|
+
}
|
|
1289
|
+
const paddingLength = Math.max(0, availableWidth - stringWidth(displayName) - 1);
|
|
1290
|
+
const padding = BOX_HORIZONTAL.repeat(paddingLength);
|
|
1291
|
+
return ANSI.CYAN + prefix + ANSI.BOLD + displayName + ANSI.RESET + " " + ANSI.CYAN + padding + suffix + ANSI.RESET;
|
|
1292
|
+
}
|
|
1293
|
+
function renderBottomBar(startLine, endLine, totalLines, _state, width) {
|
|
1294
|
+
const prefix = BOX_HORIZONTAL.repeat(3) + " ";
|
|
1295
|
+
const positionIndicator = `${startLine}-${endLine}/${totalLines}`;
|
|
1296
|
+
const content = positionIndicator;
|
|
1297
|
+
const suffix = " " + BOX_HORIZONTAL.repeat(3);
|
|
1298
|
+
const availableWidth = width - stringWidth(prefix) - stringWidth(suffix);
|
|
1299
|
+
const paddingLength = Math.max(0, availableWidth - stringWidth(content));
|
|
1300
|
+
const padding = BOX_HORIZONTAL.repeat(paddingLength);
|
|
1301
|
+
return ANSI.CYAN + prefix + ANSI.RESET + ANSI.DIM + content + ANSI.RESET + ANSI.CYAN + padding + suffix + ANSI.RESET;
|
|
1302
|
+
}
|
|
1303
|
+
function clearDiffWindow() {
|
|
1304
|
+
process.stdout.write("\n");
|
|
1305
|
+
}
|
|
1306
|
+
function colorize(line, terminalWidth) {
|
|
1307
|
+
const maxWidth = Math.max(10, terminalWidth - 3);
|
|
1308
|
+
const text = truncateLine(line.text, maxWidth);
|
|
1309
|
+
switch (line.type) {
|
|
1310
|
+
case "add":
|
|
1311
|
+
return ANSI.GREEN + text + ANSI.RESET;
|
|
1312
|
+
case "remove":
|
|
1313
|
+
return ANSI.RED + text + ANSI.RESET;
|
|
1314
|
+
case "header":
|
|
1315
|
+
return ANSI.CYAN + text + ANSI.RESET;
|
|
1316
|
+
case "context":
|
|
1317
|
+
return ANSI.GRAY + text + ANSI.RESET;
|
|
1318
|
+
default:
|
|
1319
|
+
return text;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
function truncateLine(text, maxWidth) {
|
|
1323
|
+
if (stringWidth(text) <= maxWidth) {
|
|
1324
|
+
return text;
|
|
1325
|
+
}
|
|
1326
|
+
let truncated = text;
|
|
1327
|
+
while (stringWidth(truncated + "...") > maxWidth && truncated.length > 0) {
|
|
1328
|
+
truncated = truncated.slice(0, -1);
|
|
1329
|
+
}
|
|
1330
|
+
return truncated + "...";
|
|
1331
|
+
}
|
|
1332
|
+
function getTerminalSize() {
|
|
1333
|
+
let columns = 80;
|
|
1334
|
+
let rows = 24;
|
|
1335
|
+
try {
|
|
1336
|
+
const sttyOutput = execSync("stty size </dev/tty", {
|
|
1337
|
+
encoding: "utf-8",
|
|
1338
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1339
|
+
timeout: 200,
|
|
1340
|
+
shell: "/bin/bash"
|
|
1341
|
+
}).trim();
|
|
1342
|
+
const parts = sttyOutput.split(/\s+/);
|
|
1343
|
+
if (parts.length === 2) {
|
|
1344
|
+
const sttyRows = parseInt(parts[0], 10);
|
|
1345
|
+
const sttyCols = parseInt(parts[1], 10);
|
|
1346
|
+
if (!isNaN(sttyRows) && sttyRows > 0) {
|
|
1347
|
+
rows = sttyRows;
|
|
1348
|
+
}
|
|
1349
|
+
if (!isNaN(sttyCols) && sttyCols > 0) {
|
|
1350
|
+
columns = sttyCols;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
} catch {
|
|
1354
|
+
try {
|
|
1355
|
+
const tputCols = execSync("tput cols </dev/tty", {
|
|
1356
|
+
encoding: "utf-8",
|
|
1357
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1358
|
+
timeout: 100,
|
|
1359
|
+
shell: "/bin/bash"
|
|
1360
|
+
}).trim();
|
|
1361
|
+
const cols = parseInt(tputCols, 10);
|
|
1362
|
+
if (!isNaN(cols) && cols > 0) {
|
|
1363
|
+
columns = cols;
|
|
1364
|
+
}
|
|
1365
|
+
} catch {
|
|
1366
|
+
}
|
|
1367
|
+
try {
|
|
1368
|
+
const tputRows = execSync("tput lines </dev/tty", {
|
|
1369
|
+
encoding: "utf-8",
|
|
1370
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1371
|
+
timeout: 100,
|
|
1372
|
+
shell: "/bin/bash"
|
|
1373
|
+
}).trim();
|
|
1374
|
+
const lns = parseInt(tputRows, 10);
|
|
1375
|
+
if (!isNaN(lns) && lns > 0) {
|
|
1376
|
+
rows = lns;
|
|
1377
|
+
}
|
|
1378
|
+
} catch {
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
return { rows, columns };
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// src/templates/diff-viewer/diff-prompt.ts
|
|
1385
|
+
import { _createLogger as _createLogger2 } from "@stripe/extensibility-tool-utils";
|
|
1386
|
+
var logger2 = _createLogger2({ name: "diff-prompt" });
|
|
1387
|
+
function isInteractiveTerminal() {
|
|
1388
|
+
if (process.env["CI"] === "true" || process.env["CI"] === "1") {
|
|
1389
|
+
return false;
|
|
1390
|
+
}
|
|
1391
|
+
const term = process.env["TERM"];
|
|
1392
|
+
if (!term || term === "dumb") {
|
|
1393
|
+
return false;
|
|
1394
|
+
}
|
|
1395
|
+
if (typeof process.stdin.setRawMode !== "function") {
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1398
|
+
const termSize = getTerminalSize();
|
|
1399
|
+
if (termSize.rows === 24 && termSize.columns === 80) {
|
|
1400
|
+
}
|
|
1401
|
+
return true;
|
|
1402
|
+
}
|
|
1403
|
+
async function _advancedDiffPrompt(filePath, cwd, newContent) {
|
|
1404
|
+
const resolvedPath = path2.resolve(cwd, filePath);
|
|
1405
|
+
if (!isInteractiveTerminal()) {
|
|
1406
|
+
return await _promptOverwrite(filePath);
|
|
1407
|
+
}
|
|
1408
|
+
try {
|
|
1409
|
+
const existingContent = await readExistingFile(resolvedPath);
|
|
1410
|
+
const diffResult = await generateDiff(filePath, existingContent, newContent);
|
|
1411
|
+
const termSize = getTerminalSize();
|
|
1412
|
+
if (termSize.rows < 20) {
|
|
1413
|
+
return await _promptOverwrite(filePath);
|
|
1414
|
+
}
|
|
1415
|
+
if (diffResult.lines.length > 5e3) {
|
|
1416
|
+
logger2.info("Diff too large to display comfortably");
|
|
1417
|
+
return await _promptOverwrite(filePath);
|
|
1418
|
+
}
|
|
1419
|
+
const wasRaw = process.stdin.isRaw ?? false;
|
|
1420
|
+
try {
|
|
1421
|
+
process.stdin.setRawMode(true);
|
|
1422
|
+
} catch {
|
|
1423
|
+
return await _promptOverwrite(filePath);
|
|
1424
|
+
}
|
|
1425
|
+
process.stdin.resume();
|
|
1426
|
+
const maxTotalHeight = Math.floor(termSize.rows * 0.75);
|
|
1427
|
+
const maxContentHeight = maxTotalHeight - 3;
|
|
1428
|
+
const windowHeight = Math.min(diffResult.lines.length, maxContentHeight);
|
|
1429
|
+
const state = {
|
|
1430
|
+
scrollOffset: 0,
|
|
1431
|
+
maxScroll: Math.max(0, diffResult.lines.length - windowHeight),
|
|
1432
|
+
diffLines: diffResult.lines,
|
|
1433
|
+
terminalHeight: termSize.rows,
|
|
1434
|
+
terminalWidth: termSize.columns,
|
|
1435
|
+
wasRaw,
|
|
1436
|
+
renderedHeight: 0,
|
|
1437
|
+
fullFileMode: false
|
|
1438
|
+
};
|
|
1439
|
+
render(state, filePath, false);
|
|
1440
|
+
return new Promise((resolve) => {
|
|
1441
|
+
const onExit = () => {
|
|
1442
|
+
cleanup(state.wasRaw, onData, onExit);
|
|
1443
|
+
};
|
|
1444
|
+
const onData = (buffer) => {
|
|
1445
|
+
handleKeypress(buffer, state, filePath, newContent, existingContent).then((result) => {
|
|
1446
|
+
if (result !== "continue") {
|
|
1447
|
+
cleanup(state.wasRaw, onData, onExit);
|
|
1448
|
+
resolve(result);
|
|
1449
|
+
}
|
|
1450
|
+
}).catch((err) => {
|
|
1451
|
+
cleanup(state.wasRaw, onData, onExit);
|
|
1452
|
+
logger2.error({ err }, "Error handling keypress");
|
|
1453
|
+
resolve("abort");
|
|
1454
|
+
});
|
|
1455
|
+
};
|
|
1456
|
+
process.stdin.on("data", onData);
|
|
1457
|
+
process.on("exit", onExit);
|
|
1458
|
+
});
|
|
1459
|
+
} catch (err) {
|
|
1460
|
+
logger2.warn({ err }, "Error displaying diff, using basic prompt");
|
|
1461
|
+
return await _promptOverwrite(filePath);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
async function handleKeypress(buffer, state, filePath, newContent, existingContent) {
|
|
1465
|
+
const code = buffer[0];
|
|
1466
|
+
const key = buffer.toString();
|
|
1467
|
+
if (code === 3) {
|
|
1468
|
+
process.stdout.write("\nCancelled.\n");
|
|
1469
|
+
return "abort";
|
|
1470
|
+
}
|
|
1471
|
+
switch (key.toLowerCase()) {
|
|
1472
|
+
case "y":
|
|
1473
|
+
return "overwrite";
|
|
1474
|
+
case "n":
|
|
1475
|
+
case "\r":
|
|
1476
|
+
case "\n":
|
|
1477
|
+
return "skip";
|
|
1478
|
+
case "a":
|
|
1479
|
+
return "overwrite-all";
|
|
1480
|
+
case "q":
|
|
1481
|
+
return "abort";
|
|
1482
|
+
case "d":
|
|
1483
|
+
await toggleDiffContext(state, filePath, newContent, existingContent);
|
|
1484
|
+
return "continue";
|
|
1485
|
+
}
|
|
1486
|
+
if (buffer.length >= 3 && buffer[0] === 27 && buffer[1] === 91) {
|
|
1487
|
+
const maxTotalHeight = Math.floor(state.terminalHeight * 0.75);
|
|
1488
|
+
const maxContentHeight = maxTotalHeight - 3;
|
|
1489
|
+
const windowHeight = Math.min(state.diffLines.length, maxContentHeight);
|
|
1490
|
+
let scrollDelta = 0;
|
|
1491
|
+
if (buffer[2] === 65) {
|
|
1492
|
+
scrollDelta = -1;
|
|
1493
|
+
} else if (buffer[2] === 66) {
|
|
1494
|
+
scrollDelta = 1;
|
|
1495
|
+
} else if (buffer[2] === 53) {
|
|
1496
|
+
scrollDelta = -windowHeight;
|
|
1497
|
+
} else if (buffer[2] === 54) {
|
|
1498
|
+
scrollDelta = windowHeight;
|
|
1499
|
+
}
|
|
1500
|
+
const newScrollOffset = Math.max(
|
|
1501
|
+
0,
|
|
1502
|
+
Math.min(state.maxScroll, state.scrollOffset + scrollDelta)
|
|
1503
|
+
);
|
|
1504
|
+
if (newScrollOffset !== state.scrollOffset) {
|
|
1505
|
+
state.scrollOffset = newScrollOffset;
|
|
1506
|
+
render(state, filePath, true);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return "continue";
|
|
1510
|
+
}
|
|
1511
|
+
function cleanup(wasRaw, onData, onExit) {
|
|
1512
|
+
if (process.stdin.setRawMode !== void 0) {
|
|
1513
|
+
process.stdin.setRawMode(wasRaw);
|
|
1514
|
+
}
|
|
1515
|
+
process.stdin.pause();
|
|
1516
|
+
if (onData) {
|
|
1517
|
+
process.stdin.off("data", onData);
|
|
1518
|
+
}
|
|
1519
|
+
if (onExit) {
|
|
1520
|
+
process.off("exit", onExit);
|
|
1521
|
+
}
|
|
1522
|
+
clearDiffWindow();
|
|
1523
|
+
}
|
|
1524
|
+
async function toggleDiffContext(state, filePath, newContent, existingContent) {
|
|
1525
|
+
state.fullFileMode = !state.fullFileMode;
|
|
1526
|
+
const contextLines = state.fullFileMode ? 1e4 : 3;
|
|
1527
|
+
const visibleStartIndex = state.scrollOffset;
|
|
1528
|
+
let referenceLineFinder = null;
|
|
1529
|
+
let skippedLines = 0;
|
|
1530
|
+
for (let i = visibleStartIndex; i < state.diffLines.length; i++) {
|
|
1531
|
+
const line = state.diffLines[i];
|
|
1532
|
+
if (line !== void 0) {
|
|
1533
|
+
if (line.type === "header") {
|
|
1534
|
+
skippedLines++;
|
|
1535
|
+
continue;
|
|
1536
|
+
}
|
|
1537
|
+
if (line.newLine !== void 0) {
|
|
1538
|
+
const targetNewLine = line.newLine;
|
|
1539
|
+
referenceLineFinder = (dl) => dl.newLine !== void 0 && dl.newLine >= targetNewLine - skippedLines;
|
|
1540
|
+
break;
|
|
1541
|
+
} else if (line.oldLine !== void 0) {
|
|
1542
|
+
const targetOldLine = line.oldLine;
|
|
1543
|
+
referenceLineFinder = (dl) => dl.oldLine !== void 0 && dl.oldLine >= targetOldLine - skippedLines;
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
const diffResult = await generateDiff(
|
|
1549
|
+
filePath,
|
|
1550
|
+
existingContent,
|
|
1551
|
+
newContent,
|
|
1552
|
+
contextLines
|
|
1553
|
+
);
|
|
1554
|
+
state.diffLines = diffResult.lines;
|
|
1555
|
+
let newScrollOffset = 0;
|
|
1556
|
+
if (referenceLineFinder !== null) {
|
|
1557
|
+
const referenceIndex = diffResult.lines.findIndex(referenceLineFinder);
|
|
1558
|
+
if (referenceIndex !== -1) {
|
|
1559
|
+
newScrollOffset = Math.max(0, referenceIndex);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
const maxTotalHeight = Math.floor(state.terminalHeight * 0.75);
|
|
1563
|
+
const maxContentHeight = maxTotalHeight - 3;
|
|
1564
|
+
const windowHeight = Math.min(diffResult.lines.length, maxContentHeight);
|
|
1565
|
+
state.maxScroll = Math.max(0, diffResult.lines.length - windowHeight);
|
|
1566
|
+
state.scrollOffset = Math.min(newScrollOffset, state.maxScroll);
|
|
1567
|
+
render(state, filePath, true);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// src/templates/extensions/types.ts
|
|
1571
|
+
var _ExtensionTemplateManager = class extends _TemplateManager {
|
|
1572
|
+
/**
|
|
1573
|
+
* Get summary info for all registered extension templates
|
|
1574
|
+
*/
|
|
1575
|
+
getTemplateInfo() {
|
|
1576
|
+
return this.getTemplateEntries().map(([key, t]) => ({
|
|
1577
|
+
key,
|
|
1578
|
+
description: t.description,
|
|
1579
|
+
deprecated: t.deprecated ?? false,
|
|
1580
|
+
hidden: t.hidden ?? false,
|
|
1581
|
+
methods: t.methods
|
|
1582
|
+
}));
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
|
|
1586
|
+
// src/dependencies/index.ts
|
|
1587
|
+
import path3 from "path";
|
|
1588
|
+
import fs from "fs";
|
|
1589
|
+
import os from "os";
|
|
1590
|
+
import { execSync as execSync2 } from "child_process";
|
|
1591
|
+
import PackageJson from "@npmcli/package-json";
|
|
1592
|
+
import * as semver from "semver";
|
|
1593
|
+
import { load as parseToml } from "js-toml";
|
|
1594
|
+
import { _createCliContext } from "@stripe/extensibility-tool-utils";
|
|
1595
|
+
function _npmDep(name, version) {
|
|
1596
|
+
return { type: "npm", name, version };
|
|
1597
|
+
}
|
|
1598
|
+
function _devNpmDep(name, version) {
|
|
1599
|
+
return { type: "dev-npm", name, version };
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
// src/templates/extensions/base.ts
|
|
1603
|
+
import { _workspaceVersion } from "@stripe/extensibility-tool-utils";
|
|
1604
|
+
var SDK_PACKAGE_NAME = "@stripe/extensibility-sdk";
|
|
1605
|
+
var LANGUAGE_SERVER_PACKAGE_NAME = "@stripe/extensibility-language-server";
|
|
1606
|
+
var LANGUAGE_SERVER_PACKAGE_VERSION = "^0.2.0";
|
|
1607
|
+
function _createExtensionEslintConfigFile(params, context) {
|
|
1608
|
+
const { id, extensionInterfaceId } = params;
|
|
1609
|
+
const { fs: fs2 } = context;
|
|
1610
|
+
return {
|
|
1611
|
+
path: `extensions/${id}/eslint.config.mts`,
|
|
1612
|
+
content: fs2.mustache(
|
|
1613
|
+
{ extensionInterfaceId },
|
|
1614
|
+
"common",
|
|
1615
|
+
"eslint.config.mts.mustache"
|
|
1616
|
+
),
|
|
1617
|
+
precious: true
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
function _createBaseOutput(params, context) {
|
|
1621
|
+
const { id } = params;
|
|
1622
|
+
const { fs: fs2 } = context;
|
|
1623
|
+
return {
|
|
1624
|
+
files: [
|
|
1625
|
+
{
|
|
1626
|
+
path: `extensions/${id}/package.json`,
|
|
1627
|
+
content: fs2.mustache(params, "common", "package.json.mustache")
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
..._createExtensionEslintConfigFile(params, context)
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
path: `extensions/${id}/tsconfig.build.json`,
|
|
1634
|
+
content: fs2.mustache(params, "common", "tsconfig.build.json.mustache")
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
path: `extensions/${id}/tsconfig.json`,
|
|
1638
|
+
content: fs2.mustache(params, "common", "tsconfig.json.mustache")
|
|
1639
|
+
},
|
|
1640
|
+
{
|
|
1641
|
+
path: `extensions/${id}/.prettierignore`,
|
|
1642
|
+
content: fs2.textFile("common", ".prettierignore")
|
|
1643
|
+
}
|
|
1644
|
+
],
|
|
1645
|
+
methods: {},
|
|
1646
|
+
dependencies: {
|
|
1647
|
+
// Exact pin (no caret) — the SDK is tightly coupled to dev-tools and
|
|
1648
|
+
// must match the version that generated the extension scaffolding.
|
|
1649
|
+
runtime: [_npmDep(SDK_PACKAGE_NAME, _workspaceVersion(SDK_PACKAGE_NAME))],
|
|
1650
|
+
dev: [_devNpmDep(LANGUAGE_SERVER_PACKAGE_NAME, LANGUAGE_SERVER_PACKAGE_VERSION)]
|
|
1651
|
+
},
|
|
1652
|
+
postGenerationHooks: [
|
|
1653
|
+
{
|
|
1654
|
+
script: "build",
|
|
1655
|
+
description: "Build extension"
|
|
1656
|
+
},
|
|
1657
|
+
{
|
|
1658
|
+
exec: "prettier --write .",
|
|
1659
|
+
description: "Format generated files"
|
|
1660
|
+
}
|
|
1661
|
+
]
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// src/templates/extensions/core.workflows.custom_action.ts
|
|
1666
|
+
var EXTENSION_INTERFACE_ID = "core.workflows.custom_action";
|
|
1667
|
+
var customActionTemplate = {
|
|
1668
|
+
methods: {
|
|
1669
|
+
execute: { implementation_types: ["script", "remote-function"] },
|
|
1670
|
+
get_form_state: { implementation_types: ["script", "remote-function"] }
|
|
1671
|
+
},
|
|
1672
|
+
description: "Custom actions let your app define actions that users can add to their automated workflows. When a workflow triggers a custom action, Stripe calls your app to execute it.",
|
|
1673
|
+
generate: (params, context) => {
|
|
1674
|
+
const { id } = params;
|
|
1675
|
+
const { fs: fs2 } = context;
|
|
1676
|
+
const base = _createBaseOutput(
|
|
1677
|
+
{
|
|
1678
|
+
...params,
|
|
1679
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID,
|
|
1680
|
+
executionProfile: "egress"
|
|
1681
|
+
},
|
|
1682
|
+
context
|
|
1683
|
+
);
|
|
1684
|
+
return {
|
|
1685
|
+
...base,
|
|
1686
|
+
files: [
|
|
1687
|
+
{
|
|
1688
|
+
path: `extensions/${id}/src/index.ts`,
|
|
1689
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID, "index.ts"),
|
|
1690
|
+
precious: true
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
path: `extensions/${id}/src/custom_input.schema.json`,
|
|
1694
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID, "custom_input.schema.json"),
|
|
1695
|
+
precious: true
|
|
1696
|
+
},
|
|
1697
|
+
{
|
|
1698
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
1699
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID, "index.test.ts"),
|
|
1700
|
+
precious: true
|
|
1701
|
+
},
|
|
1702
|
+
...base.files
|
|
1703
|
+
],
|
|
1704
|
+
methods: {
|
|
1705
|
+
execute: {
|
|
1706
|
+
implementation_type: "script",
|
|
1707
|
+
custom_input: {
|
|
1708
|
+
input_schema: {
|
|
1709
|
+
type: "json_schema",
|
|
1710
|
+
content: `extensions/${id}/src/custom_input.schema.json`
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
},
|
|
1714
|
+
get_form_state: {
|
|
1715
|
+
implementation_type: "script"
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
}
|
|
1720
|
+
};
|
|
1721
|
+
var core_workflows_custom_action_default = {
|
|
1722
|
+
[EXTENSION_INTERFACE_ID]: customActionTemplate
|
|
1723
|
+
};
|
|
1724
|
+
|
|
1725
|
+
// src/templates/extensions/extend.objects.custom_objects.ts
|
|
1726
|
+
var EXTENSION_INTERFACE_ID2 = "extend.objects.custom_objects";
|
|
1727
|
+
var customObjectsTemplate = {
|
|
1728
|
+
methods: {
|
|
1729
|
+
execute_method: { implementation_types: ["script"] }
|
|
1730
|
+
},
|
|
1731
|
+
description: "Methods extension for custom object actions. Generated at build time \u2014 the transformed custom object class becomes the entry point.",
|
|
1732
|
+
hidden: true,
|
|
1733
|
+
generate: (params, context) => {
|
|
1734
|
+
const base = _createBaseOutput(
|
|
1735
|
+
{
|
|
1736
|
+
...params,
|
|
1737
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID2,
|
|
1738
|
+
executionProfile: "egress"
|
|
1739
|
+
},
|
|
1740
|
+
context
|
|
1741
|
+
);
|
|
1742
|
+
return {
|
|
1743
|
+
...base,
|
|
1744
|
+
methods: {
|
|
1745
|
+
execute_method: {
|
|
1746
|
+
implementation_type: "script"
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
};
|
|
1752
|
+
var extend_objects_custom_objects_default = {
|
|
1753
|
+
[EXTENSION_INTERFACE_ID2]: customObjectsTemplate
|
|
1754
|
+
};
|
|
1755
|
+
|
|
1756
|
+
// src/templates/extensions/extend.workflows.custom_action.ts
|
|
1757
|
+
var EXTENSION_INTERFACE_ID3 = "extend.workflows.custom_action";
|
|
1758
|
+
var extendCustomActionTemplate = {
|
|
1759
|
+
methods: {
|
|
1760
|
+
execute: { implementation_types: ["script", "remote-function"] },
|
|
1761
|
+
get_form_state: { implementation_types: ["script", "remote-function"] }
|
|
1762
|
+
},
|
|
1763
|
+
description: "Custom actions let your app define actions that users can add to their automated workflows. When a workflow triggers a custom action, Stripe calls your app to execute it.",
|
|
1764
|
+
generate: (params, context) => {
|
|
1765
|
+
const { id } = params;
|
|
1766
|
+
const { fs: fs2 } = context;
|
|
1767
|
+
const base = _createBaseOutput(
|
|
1768
|
+
{
|
|
1769
|
+
...params,
|
|
1770
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID3,
|
|
1771
|
+
executionProfile: "egress"
|
|
1772
|
+
},
|
|
1773
|
+
context
|
|
1774
|
+
);
|
|
1775
|
+
return {
|
|
1776
|
+
...base,
|
|
1777
|
+
files: [
|
|
1778
|
+
{
|
|
1779
|
+
path: `extensions/${id}/src/index.ts`,
|
|
1780
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID3, "index.ts"),
|
|
1781
|
+
precious: true
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
path: `extensions/${id}/src/custom_input.schema.json`,
|
|
1785
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID3, "custom_input.schema.json"),
|
|
1786
|
+
precious: true
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
1790
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID3, "index.test.ts"),
|
|
1791
|
+
precious: true
|
|
1792
|
+
},
|
|
1793
|
+
...base.files
|
|
1794
|
+
],
|
|
1795
|
+
methods: {
|
|
1796
|
+
execute: {
|
|
1797
|
+
implementation_type: "script",
|
|
1798
|
+
custom_input: {
|
|
1799
|
+
input_schema: {
|
|
1800
|
+
type: "json_schema",
|
|
1801
|
+
content: `extensions/${id}/src/custom_input.schema.json`
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
},
|
|
1805
|
+
get_form_state: {
|
|
1806
|
+
implementation_type: "script"
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
var extend_workflows_custom_action_default = {
|
|
1813
|
+
[EXTENSION_INTERFACE_ID3]: extendCustomActionTemplate
|
|
1814
|
+
};
|
|
1815
|
+
|
|
1816
|
+
// src/templates/extensions/billing.customer_balance_application.ts
|
|
1817
|
+
var EXTENSION_INTERFACE_ID4 = "billing.customer_balance_application";
|
|
1818
|
+
var customerBalanceApplicationTemplate = {
|
|
1819
|
+
methods: {
|
|
1820
|
+
compute_applied_customer_balance: { implementation_types: ["script"] }
|
|
1821
|
+
},
|
|
1822
|
+
description: "Implement custom logic to control when and how much customer balance is applied to subscription invoices using scripts.",
|
|
1823
|
+
generate: (params, context) => {
|
|
1824
|
+
const { id } = params;
|
|
1825
|
+
const { fs: fs2 } = context;
|
|
1826
|
+
const base = _createBaseOutput(
|
|
1827
|
+
{
|
|
1828
|
+
...params,
|
|
1829
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID4,
|
|
1830
|
+
executionProfile: "restricted"
|
|
1831
|
+
},
|
|
1832
|
+
context
|
|
1833
|
+
);
|
|
1834
|
+
return {
|
|
1835
|
+
...base,
|
|
1836
|
+
files: [
|
|
1837
|
+
{
|
|
1838
|
+
path: `extensions/${id}/src/index.ts`,
|
|
1839
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID4, "index.ts"),
|
|
1840
|
+
precious: true
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
1844
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID4, "index.test.ts"),
|
|
1845
|
+
precious: true
|
|
1846
|
+
},
|
|
1847
|
+
...base.files
|
|
1848
|
+
],
|
|
1849
|
+
methods: {
|
|
1850
|
+
compute_applied_customer_balance: {
|
|
1851
|
+
implementation_type: "script"
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
var billing_customer_balance_application_default = {
|
|
1858
|
+
[EXTENSION_INTERFACE_ID4]: customerBalanceApplicationTemplate
|
|
1859
|
+
};
|
|
1860
|
+
|
|
1861
|
+
// src/templates/extensions/billing.bill.discount_calculation.ts
|
|
1862
|
+
var EXTENSION_INTERFACE_ID5 = "billing.bill.discount_calculation";
|
|
1863
|
+
var discountCalculationTemplate = {
|
|
1864
|
+
hidden: true,
|
|
1865
|
+
methods: {
|
|
1866
|
+
compute_discounts: { implementation_types: ["script"] }
|
|
1867
|
+
},
|
|
1868
|
+
description: "Create coupons with custom scripting logic for dynamic discounts based on subscription attributes, customer metadata, and complex business rules.",
|
|
1869
|
+
generate: (params, context) => {
|
|
1870
|
+
const { id } = params;
|
|
1871
|
+
const { fs: fs2 } = context;
|
|
1872
|
+
const base = _createBaseOutput(
|
|
1873
|
+
{
|
|
1874
|
+
...params,
|
|
1875
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID5,
|
|
1876
|
+
executionProfile: "restricted"
|
|
1877
|
+
},
|
|
1878
|
+
context
|
|
1879
|
+
);
|
|
1880
|
+
return {
|
|
1881
|
+
...base,
|
|
1882
|
+
files: [
|
|
1883
|
+
{
|
|
1884
|
+
path: `extensions/${id}/src/index.ts`,
|
|
1885
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID5, "index.ts"),
|
|
1886
|
+
precious: true
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
1890
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID5, "index.test.ts"),
|
|
1891
|
+
precious: true
|
|
1892
|
+
},
|
|
1893
|
+
...base.files
|
|
1894
|
+
],
|
|
1895
|
+
methods: {
|
|
1896
|
+
compute_discounts: {
|
|
1897
|
+
implementation_type: "script"
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
var billing_bill_discount_calculation_default = {
|
|
1904
|
+
[EXTENSION_INTERFACE_ID5]: discountCalculationTemplate
|
|
1905
|
+
};
|
|
1906
|
+
|
|
1907
|
+
// src/templates/extensions/billing.invoice_collection_setting.ts
|
|
1908
|
+
var EXTENSION_INTERFACE_ID6 = "billing.invoice_collection_setting";
|
|
1909
|
+
var invoiceCollectionSettingTemplate = {
|
|
1910
|
+
hidden: true,
|
|
1911
|
+
methods: {
|
|
1912
|
+
collection_override: { implementation_types: ["script"] }
|
|
1913
|
+
},
|
|
1914
|
+
description: "Use Stripe Scripts to create custom invoice collection logic that controls how your integration handles invoices generated from subscriptions.",
|
|
1915
|
+
generate: (params, context) => {
|
|
1916
|
+
const { id } = params;
|
|
1917
|
+
const { fs: fs2 } = context;
|
|
1918
|
+
const base = _createBaseOutput(
|
|
1919
|
+
{
|
|
1920
|
+
...params,
|
|
1921
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID6,
|
|
1922
|
+
executionProfile: "restricted"
|
|
1923
|
+
},
|
|
1924
|
+
context
|
|
1925
|
+
);
|
|
1926
|
+
return {
|
|
1927
|
+
...base,
|
|
1928
|
+
files: [
|
|
1929
|
+
{
|
|
1930
|
+
path: `extensions/${id}/src/index.ts`,
|
|
1931
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID6, "index.ts"),
|
|
1932
|
+
precious: true
|
|
1933
|
+
},
|
|
1934
|
+
{
|
|
1935
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
1936
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID6, "index.test.ts"),
|
|
1937
|
+
precious: true
|
|
1938
|
+
},
|
|
1939
|
+
...base.files
|
|
1940
|
+
],
|
|
1941
|
+
methods: {
|
|
1942
|
+
collection_override: {
|
|
1943
|
+
implementation_type: "script"
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
};
|
|
1949
|
+
var billing_invoice_collection_setting_default = {
|
|
1950
|
+
[EXTENSION_INTERFACE_ID6]: invoiceCollectionSettingTemplate
|
|
1951
|
+
};
|
|
1952
|
+
|
|
1953
|
+
// src/templates/extensions/billing.prorations.ts
|
|
1954
|
+
var EXTENSION_INTERFACE_ID7 = "billing.prorations";
|
|
1955
|
+
var prorationsTemplate = {
|
|
1956
|
+
methods: {
|
|
1957
|
+
prorate_items: { implementation_types: ["script"] }
|
|
1958
|
+
},
|
|
1959
|
+
description: "Create custom proration logic for subscriptions using scripts to handle upgrades, downgrades, and mid-cycle changes.",
|
|
1960
|
+
generate: (params, context) => {
|
|
1961
|
+
const { id } = params;
|
|
1962
|
+
const { fs: fs2 } = context;
|
|
1963
|
+
const base = _createBaseOutput(
|
|
1964
|
+
{
|
|
1965
|
+
...params,
|
|
1966
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID7,
|
|
1967
|
+
executionProfile: "restricted"
|
|
1968
|
+
},
|
|
1969
|
+
context
|
|
1970
|
+
);
|
|
1971
|
+
return {
|
|
1972
|
+
...base,
|
|
1973
|
+
files: [
|
|
1974
|
+
{
|
|
1975
|
+
path: `extensions/${id}/src/index.ts`,
|
|
1976
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID7, "index.ts"),
|
|
1977
|
+
precious: true
|
|
1978
|
+
},
|
|
1979
|
+
{
|
|
1980
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
1981
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID7, "index.test.ts"),
|
|
1982
|
+
precious: true
|
|
1983
|
+
},
|
|
1984
|
+
...base.files
|
|
1985
|
+
],
|
|
1986
|
+
methods: {
|
|
1987
|
+
prorate_items: {
|
|
1988
|
+
implementation_type: "script"
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
var billing_prorations_default = {
|
|
1995
|
+
[EXTENSION_INTERFACE_ID7]: prorationsTemplate
|
|
1996
|
+
};
|
|
1997
|
+
|
|
1998
|
+
// src/templates/extensions/billing.recurring_billing_item_handling.ts
|
|
1999
|
+
var EXTENSION_INTERFACE_ID8 = "billing.recurring_billing_item_handling";
|
|
2000
|
+
var template = {
|
|
2001
|
+
methods: {
|
|
2002
|
+
before_item_creation: { implementation_types: ["script"] },
|
|
2003
|
+
filter_items: { implementation_types: ["script"] },
|
|
2004
|
+
group_items: { implementation_types: ["script"] }
|
|
2005
|
+
},
|
|
2006
|
+
description: "Customize how recurring billing items are filtered, grouped, and created during subscription billing runs.",
|
|
2007
|
+
generate: (params, context) => {
|
|
2008
|
+
const { id } = params;
|
|
2009
|
+
const { fs: fs2 } = context;
|
|
2010
|
+
const base = _createBaseOutput(
|
|
2011
|
+
{
|
|
2012
|
+
...params,
|
|
2013
|
+
extensionInterfaceId: EXTENSION_INTERFACE_ID8,
|
|
2014
|
+
executionProfile: "restricted"
|
|
2015
|
+
},
|
|
2016
|
+
context
|
|
2017
|
+
);
|
|
2018
|
+
return {
|
|
2019
|
+
...base,
|
|
2020
|
+
files: [
|
|
2021
|
+
{
|
|
2022
|
+
path: `extensions/${id}/src/index.ts`,
|
|
2023
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID8, "index.ts"),
|
|
2024
|
+
precious: true
|
|
2025
|
+
},
|
|
2026
|
+
{
|
|
2027
|
+
path: `extensions/${id}/src/index.test.ts`,
|
|
2028
|
+
content: fs2.textFile(EXTENSION_INTERFACE_ID8, "index.test.ts"),
|
|
2029
|
+
precious: true
|
|
2030
|
+
},
|
|
2031
|
+
...base.files
|
|
2032
|
+
],
|
|
2033
|
+
methods: {
|
|
2034
|
+
before_item_creation: {
|
|
2035
|
+
implementation_type: "script"
|
|
2036
|
+
},
|
|
2037
|
+
filter_items: {
|
|
2038
|
+
implementation_type: "script"
|
|
2039
|
+
},
|
|
2040
|
+
group_items: {
|
|
2041
|
+
implementation_type: "script"
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
var billing_recurring_billing_item_handling_default = {
|
|
2048
|
+
[EXTENSION_INTERFACE_ID8]: template
|
|
2049
|
+
};
|
|
2050
|
+
|
|
2051
|
+
// src/templates/extensions/registry.ts
|
|
2052
|
+
var DEFAULT_TEMPLATES = {
|
|
2053
|
+
...core_workflows_custom_action_default,
|
|
2054
|
+
...extend_objects_custom_objects_default,
|
|
2055
|
+
...extend_workflows_custom_action_default,
|
|
2056
|
+
...billing_customer_balance_application_default,
|
|
2057
|
+
...billing_bill_discount_calculation_default,
|
|
2058
|
+
...billing_invoice_collection_setting_default,
|
|
2059
|
+
...billing_prorations_default,
|
|
2060
|
+
...billing_recurring_billing_item_handling_default
|
|
2061
|
+
};
|
|
2062
|
+
var registry_default = DEFAULT_TEMPLATES;
|
|
2063
|
+
|
|
2064
|
+
// src/templates/extensions/index.ts
|
|
2065
|
+
var _templateManager = new _ExtensionTemplateManager(
|
|
2066
|
+
registry_default,
|
|
2067
|
+
_fs.scope("extensions")
|
|
2068
|
+
);
|
|
2069
|
+
|
|
2070
|
+
// src/templates/root/index.ts
|
|
2071
|
+
import { _workspaceVersion as _workspaceVersion2 } from "@stripe/extensibility-tool-utils";
|
|
2072
|
+
var EXTENSIBILITY_ESLINT_PLUGIN_PACKAGE_NAME = "@stripe/extensibility-eslint-plugin";
|
|
2073
|
+
var EXTENSIBILITY_ESLINT_PLUGIN_VERSION = `^${_workspaceVersion2(EXTENSIBILITY_ESLINT_PLUGIN_PACKAGE_NAME)}`;
|
|
2074
|
+
var _rootWorkspaceTemplate = {
|
|
2075
|
+
generate: (params, context) => {
|
|
2076
|
+
const { fs: fs2 } = context;
|
|
2077
|
+
return {
|
|
2078
|
+
files: [
|
|
2079
|
+
{
|
|
2080
|
+
path: "stripe-app.yaml",
|
|
2081
|
+
content: fs2.mustache(params, "stripe-app.yaml.mustache"),
|
|
2082
|
+
precious: true
|
|
2083
|
+
},
|
|
2084
|
+
{
|
|
2085
|
+
path: "package.json",
|
|
2086
|
+
content: fs2.mustache(params, "package.json.mustache")
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
path: ".husky/pre-commit",
|
|
2090
|
+
content: fs2.textFile(".husky/pre-commit")
|
|
2091
|
+
},
|
|
2092
|
+
{
|
|
2093
|
+
path: "tsconfig.base.json",
|
|
2094
|
+
content: fs2.textFile("tsconfig.base.json")
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
path: "tsconfig.json",
|
|
2098
|
+
content: fs2.textFile("tsconfig.json")
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
path: "eslint.config.mts",
|
|
2102
|
+
content: fs2.textFile("eslint.config.mts")
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
path: "vitest.config.mts",
|
|
2106
|
+
content: fs2.textFile("vitest.config.mts")
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
2109
|
+
path: ".gitignore",
|
|
2110
|
+
content: fs2.textFile("_gitignore")
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
path: "pnpm-workspace.yaml",
|
|
2114
|
+
content: fs2.textFile("pnpm-workspace.yaml")
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
path: ".prettierrc",
|
|
2118
|
+
content: fs2.textFile(".prettierrc")
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
path: ".prettierignore",
|
|
2122
|
+
content: fs2.textFile(".prettierignore")
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
path: "custom-objects/package.json",
|
|
2126
|
+
content: fs2.textFile("custom-objects/package.json"),
|
|
2127
|
+
precious: true
|
|
2128
|
+
},
|
|
2129
|
+
{
|
|
2130
|
+
path: "custom-objects/tsconfig.json",
|
|
2131
|
+
content: fs2.textFile("custom-objects/tsconfig.json"),
|
|
2132
|
+
precious: true
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
path: "ui/package.json",
|
|
2136
|
+
content: fs2.textFile("ui/package.json"),
|
|
2137
|
+
precious: true
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
path: "tools/test.mts",
|
|
2141
|
+
content: fs2.textFile("tools/test.mts")
|
|
2142
|
+
},
|
|
2143
|
+
{
|
|
2144
|
+
// temporarily add dummy JSON manifest until stripe apps plugin is fixed
|
|
2145
|
+
path: "stripe-app.json",
|
|
2146
|
+
content: "{}\n"
|
|
2147
|
+
}
|
|
2148
|
+
],
|
|
2149
|
+
dependencies: {
|
|
2150
|
+
dev: [
|
|
2151
|
+
_devNpmDep("@eslint/js", "^9.0.0"),
|
|
2152
|
+
_devNpmDep(
|
|
2153
|
+
EXTENSIBILITY_ESLINT_PLUGIN_PACKAGE_NAME,
|
|
2154
|
+
EXTENSIBILITY_ESLINT_PLUGIN_VERSION
|
|
2155
|
+
),
|
|
2156
|
+
_devNpmDep(LANGUAGE_SERVER_PACKAGE_NAME, LANGUAGE_SERVER_PACKAGE_VERSION),
|
|
2157
|
+
_devNpmDep("@types/node", "^20.19.0"),
|
|
2158
|
+
_devNpmDep(
|
|
2159
|
+
"@stripe/extensibility-dev-tools",
|
|
2160
|
+
`^${_workspaceVersion2("@stripe/extensibility-dev-tools")}`
|
|
2161
|
+
),
|
|
2162
|
+
_devNpmDep("concurrently", "^9.2.1"),
|
|
2163
|
+
_devNpmDep("eslint", "^9.0.0"),
|
|
2164
|
+
_devNpmDep("eslint-config-prettier", "^10.1.8"),
|
|
2165
|
+
_devNpmDep("eslint-plugin-workspaces", "^0.12.1"),
|
|
2166
|
+
_devNpmDep("globals", "^17.4.0"),
|
|
2167
|
+
_devNpmDep("husky", "^9.1.7"),
|
|
2168
|
+
_devNpmDep("jiti", "^2.6.1"),
|
|
2169
|
+
_devNpmDep("lint-staged", "^16.2.7"),
|
|
2170
|
+
_devNpmDep("chokidar-cli", "^3.0.0"),
|
|
2171
|
+
_devNpmDep("prettier", "^3.8.1"),
|
|
2172
|
+
_devNpmDep("ts-node", "^10.9.2"),
|
|
2173
|
+
_devNpmDep("tsx", "^4.21.0"),
|
|
2174
|
+
_devNpmDep("typescript", "^5.9.3"),
|
|
2175
|
+
_devNpmDep("typescript-eslint", "^8.54.0"),
|
|
2176
|
+
_devNpmDep("vitest", "^3.0.0")
|
|
2177
|
+
]
|
|
2178
|
+
},
|
|
2179
|
+
postGenerationHooks: [
|
|
2180
|
+
{
|
|
2181
|
+
exec: "prettier --write .",
|
|
2182
|
+
description: "Format generated files"
|
|
2183
|
+
}
|
|
2184
|
+
]
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
};
|
|
2188
|
+
var _rootTemplateManager = new _SingleTemplateManager(_rootWorkspaceTemplate, _fs.scope("root"));
|
|
2189
|
+
export {
|
|
2190
|
+
_ExtensionTemplateManager,
|
|
2191
|
+
_SingleTemplateManager,
|
|
2192
|
+
_TemplateManager,
|
|
2193
|
+
_advancedDiffPrompt,
|
|
2194
|
+
_createExtensionEslintConfigFile,
|
|
2195
|
+
_createSimpleSingleFileTemplate,
|
|
2196
|
+
_createSimpleTemplate,
|
|
2197
|
+
_fs,
|
|
2198
|
+
_promptOverwrite,
|
|
2199
|
+
_rootTemplateManager,
|
|
2200
|
+
_rootWorkspaceTemplate,
|
|
2201
|
+
_templateManager,
|
|
2202
|
+
_writeGeneratedFiles
|
|
2203
|
+
};
|