skedyul 1.7.7 → 1.7.9

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/dist/.build-stamp CHANGED
@@ -1 +1 @@
1
- 1785972320346
1
+ 1785987631012
package/dist/cli/index.js CHANGED
@@ -4658,6 +4658,39 @@ async function handleMcpBatchRoute(req, ctx) {
4658
4658
  }
4659
4659
  };
4660
4660
  }
4661
+ function isBatchOperationFailure(result) {
4662
+ return result != null && typeof result === "object" && result.success === false && typeof result.error === "object" && result.error != null;
4663
+ }
4664
+ function toStringEnv(env) {
4665
+ const out = {};
4666
+ for (const [key, value] of Object.entries(env)) {
4667
+ if (value !== void 0) {
4668
+ out[key] = value;
4669
+ }
4670
+ }
4671
+ return out;
4672
+ }
4673
+ function stripBillingFields(result) {
4674
+ const {
4675
+ billing: _billing,
4676
+ success: _success,
4677
+ error: _error,
4678
+ retry: _retry,
4679
+ ...domain
4680
+ } = result;
4681
+ return domain;
4682
+ }
4683
+ function softFailureResponse(error, retry, billing) {
4684
+ return {
4685
+ status: 200,
4686
+ body: {
4687
+ success: false,
4688
+ error,
4689
+ ...retry ? { retry } : {},
4690
+ billing: normalizeBilling(billing)
4691
+ }
4692
+ };
4693
+ }
4661
4694
  async function handleBatchOperationRoute(req, ctx) {
4662
4695
  const bodyResult = parseJsonBody(req);
4663
4696
  if (!bodyResult.success) {
@@ -4666,34 +4699,80 @@ async function handleBatchOperationRoute(req, ctx) {
4666
4699
  const body = bodyResult.data;
4667
4700
  const registry = ctx.batchOperationRegistry;
4668
4701
  if (!registry) {
4669
- return {
4670
- status: 404,
4671
- body: {
4672
- success: false,
4673
- error: "No batch operations registered"
4674
- }
4675
- };
4702
+ return softFailureResponse({
4703
+ code: "NOT_FOUND",
4704
+ message: "No batch operations registered",
4705
+ category: "validation"
4706
+ });
4676
4707
  }
4677
4708
  const operation = registry[body.handle];
4678
4709
  if (!operation) {
4679
- return {
4680
- status: 404,
4681
- body: {
4682
- success: false,
4683
- error: `Batch operation not found: ${body.handle}`
4684
- }
4685
- };
4710
+ return softFailureResponse({
4711
+ code: "NOT_FOUND",
4712
+ message: `Batch operation not found: ${body.handle}`,
4713
+ category: "validation"
4714
+ });
4686
4715
  }
4687
- const log = {
4688
- info: (message, meta) => {
4689
- console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
4690
- },
4691
- warn: (message, meta) => {
4692
- console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
4693
- },
4694
- error: (message, meta) => {
4695
- console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
4696
- }
4716
+ const context = body.context;
4717
+ if (!context?.workplaceId || !context?.appInstallationId || !context?.appId) {
4718
+ return softFailureResponse({
4719
+ code: "VALIDATION_ERROR",
4720
+ message: "Missing context (workplaceId, appInstallationId, and appId required)",
4721
+ category: "validation"
4722
+ });
4723
+ }
4724
+ if (body.method !== "setup" && body.method !== "iterate") {
4725
+ return softFailureResponse({
4726
+ code: "VALIDATION_ERROR",
4727
+ message: `Unknown method: ${body.method}`,
4728
+ category: "validation"
4729
+ });
4730
+ }
4731
+ const requestEnv = body.env ?? {};
4732
+ const mergedEnv = toStringEnv(buildToolExecutionEnv(requestEnv));
4733
+ const originalEnv = { ...process.env };
4734
+ Object.assign(process.env, mergedEnv);
4735
+ const log = createContextLogger();
4736
+ const app = context.app ?? {
4737
+ id: context.appId,
4738
+ versionId: context.appId
4739
+ };
4740
+ const workplace = context.workplace ?? {
4741
+ id: context.workplaceId,
4742
+ subdomain: ""
4743
+ };
4744
+ const invocation = body.invocation ?? {
4745
+ invocationId: `${body.handle}-${body.method}-${Date.now()}`,
4746
+ invocationType: "batch_operation",
4747
+ batchOperationHandle: body.handle,
4748
+ batchOperationMethod: body.method,
4749
+ appInstallationId: context.appInstallationId
4750
+ };
4751
+ const requestConfig = {
4752
+ baseUrl: mergedEnv.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? "",
4753
+ apiToken: mergedEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? ""
4754
+ };
4755
+ const rateLimitContext = {
4756
+ app,
4757
+ appInstallationId: context.appInstallationId,
4758
+ invocation,
4759
+ preAcquiredLeases: parsePreAcquiredLeases(
4760
+ mergedEnv.SKEDYUL_RATE_LIMIT_LEASES
4761
+ ),
4762
+ heldMutexQueueKeys: parseHeldMutexQueueKeys(
4763
+ mergedEnv.SKEDYUL_HELD_MUTEX_QUEUE_KEYS
4764
+ )
4765
+ };
4766
+ const opContextBase = {
4767
+ workplaceId: context.workplaceId,
4768
+ appInstallationId: context.appInstallationId,
4769
+ appId: context.appId,
4770
+ app,
4771
+ workplace,
4772
+ input: body.input,
4773
+ env: mergedEnv,
4774
+ invocation,
4775
+ log
4697
4776
  };
4698
4777
  try {
4699
4778
  if (body.method === "setup") {
@@ -4702,61 +4781,88 @@ async function handleBatchOperationRoute(req, ctx) {
4702
4781
  status: 200,
4703
4782
  body: {
4704
4783
  success: true,
4705
- result: { state: {}, total: void 0 }
4784
+ result: { state: {}, total: void 0 },
4785
+ billing: normalizeBilling(void 0)
4706
4786
  }
4707
4787
  };
4708
4788
  }
4709
- const result = await operation.setup({
4710
- workplaceId: body.workplaceId,
4711
- appInstallationId: body.appInstallationId,
4712
- appId: body.appId,
4713
- input: body.input,
4714
- log
4789
+ const raw2 = await runWithConfig(requestConfig, async () => {
4790
+ return runWithRateLimitExecutionContext(rateLimitContext, async () => {
4791
+ return runWithLogContext({ invocation }, async () => {
4792
+ return operation.setup(opContextBase);
4793
+ });
4794
+ });
4715
4795
  });
4796
+ if (isBatchOperationFailure(raw2)) {
4797
+ return softFailureResponse(raw2.error, raw2.retry, raw2.billing);
4798
+ }
4799
+ const setupResult = raw2;
4800
+ const domain2 = stripBillingFields(
4801
+ setupResult
4802
+ );
4716
4803
  return {
4717
4804
  status: 200,
4718
4805
  body: {
4719
4806
  success: true,
4720
- result
4807
+ result: domain2,
4808
+ billing: normalizeBilling(setupResult.billing)
4721
4809
  }
4722
4810
  };
4723
4811
  }
4724
- if (body.method === "iterate") {
4725
- const result = await operation.iterate({
4726
- workplaceId: body.workplaceId,
4727
- appInstallationId: body.appInstallationId,
4728
- appId: body.appId,
4729
- input: body.input,
4730
- state: body.state,
4731
- page: body.page,
4732
- cursor: body.cursor,
4733
- limit: body.limit,
4734
- log
4812
+ const raw = await runWithConfig(requestConfig, async () => {
4813
+ return runWithRateLimitExecutionContext(rateLimitContext, async () => {
4814
+ return runWithLogContext({ invocation }, async () => {
4815
+ return operation.iterate({
4816
+ ...opContextBase,
4817
+ state: body.state,
4818
+ page: body.page,
4819
+ cursor: body.cursor,
4820
+ limit: body.limit
4821
+ });
4822
+ });
4735
4823
  });
4736
- return {
4737
- status: 200,
4738
- body: {
4739
- success: true,
4740
- result
4741
- }
4742
- };
4824
+ });
4825
+ if (isBatchOperationFailure(raw)) {
4826
+ return softFailureResponse(raw.error, raw.retry, raw.billing);
4743
4827
  }
4828
+ const iterateResult = raw;
4829
+ const domain = stripBillingFields(
4830
+ iterateResult
4831
+ );
4744
4832
  return {
4745
- status: 400,
4833
+ status: 200,
4746
4834
  body: {
4747
- success: false,
4748
- error: `Unknown method: ${body.method}`
4835
+ success: true,
4836
+ result: domain,
4837
+ billing: normalizeBilling(iterateResult.billing)
4749
4838
  }
4750
4839
  };
4751
4840
  } catch (err) {
4752
- log.error("Batch operation failed", { error: err });
4841
+ if (err instanceof RateLimitExceededError) {
4842
+ return softFailureResponse(
4843
+ {
4844
+ code: "RATE_LIMITED",
4845
+ message: err.message,
4846
+ category: "external"
4847
+ },
4848
+ { allowed: true, afterMs: err.retryAfterMs }
4849
+ );
4850
+ }
4851
+ log.error("Batch operation failed", err);
4753
4852
  return {
4754
4853
  status: 500,
4755
4854
  body: {
4756
4855
  success: false,
4757
- error: err instanceof Error ? err.message : String(err)
4856
+ error: {
4857
+ code: "INTERNAL_ERROR",
4858
+ message: err instanceof Error ? err.message : String(err),
4859
+ category: "internal"
4860
+ },
4861
+ billing: normalizeBilling(void 0)
4758
4862
  }
4759
4863
  };
4864
+ } finally {
4865
+ process.env = originalEnv;
4760
4866
  }
4761
4867
  }
4762
4868
  function createNotFoundResponse() {
@@ -183,7 +183,9 @@ export declare function defineSetupStep(step: SetupStepDefinition): SetupStepDef
183
183
  * return { total: count }
184
184
  * },
185
185
  * iterate: async (ctx) => {
186
+ * const apiKey = ctx.env.GLOFOX_API_KEY
186
187
  * const { data, pagination } = await glofox.getMembers({
188
+ * apiKey,
187
189
  * limit: ctx.limit,
188
190
  * offset: ctx.cursor ?? 0,
189
191
  * })
@@ -5,6 +5,10 @@
5
5
  * like member imports, data syncs, and batch API calls. The platform handles
6
6
  * orchestration, progress tracking, CRM mapping, and upsert.
7
7
  */
8
+ import type { InvocationContext } from '../../types/invocation';
9
+ import type { ToolBilling, ToolError, ToolRetry } from '../../types/tool';
10
+ import type { AppInfo, WorkplaceInfo } from '../../types/shared';
11
+ export type { ToolBilling, ToolError, ToolRetry };
8
12
  /**
9
13
  * Pagination response from an iterate function.
10
14
  * Supports both cursor-based and page-based pagination.
@@ -21,6 +25,15 @@ export interface BatchPagination {
21
25
  /** Items per page */
22
26
  limit?: number;
23
27
  }
28
+ /**
29
+ * Soft-failure return from setup/iterate (tool-call shaped).
30
+ */
31
+ export interface BatchOperationFailure {
32
+ success: false;
33
+ error: ToolError;
34
+ retry?: ToolRetry;
35
+ billing?: ToolBilling;
36
+ }
24
37
  /**
25
38
  * Result from a batch operation setup function.
26
39
  */
@@ -29,6 +42,10 @@ export interface BatchOperationSetupResult {
29
42
  state?: Record<string, unknown>;
30
43
  /** Optional total count for progress display */
31
44
  total?: number;
45
+ /** Optional billing (normalized by the route if omitted) */
46
+ billing?: ToolBilling;
47
+ /** Optional success discriminator (default true when domain fields present) */
48
+ success?: true;
32
49
  }
33
50
  /**
34
51
  * Result from a batch operation iterate function.
@@ -40,7 +57,13 @@ export interface BatchOperationIterateResult {
40
57
  pagination: BatchPagination;
41
58
  /** Optional state to persist for the next iterate call */
42
59
  state?: Record<string, unknown>;
60
+ /** Optional billing (normalized by the route if omitted) */
61
+ billing?: ToolBilling;
62
+ /** Optional success discriminator (default true when domain fields present) */
63
+ success?: true;
43
64
  }
65
+ export type BatchOperationSetupReturn = BatchOperationSetupResult | BatchOperationFailure;
66
+ export type BatchOperationIterateReturn = BatchOperationIterateResult | BatchOperationFailure;
44
67
  /**
45
68
  * Context passed to batch operation setup and iterate functions.
46
69
  */
@@ -51,10 +74,21 @@ export interface BatchOperationContext {
51
74
  appInstallationId: string;
52
75
  /** App ID */
53
76
  appId: string;
77
+ /** App info with version (for rate-limit / SDK context) */
78
+ app?: AppInfo;
79
+ /** Workplace info when available */
80
+ workplace?: WorkplaceInfo;
54
81
  /** User-provided input (if any) */
55
82
  input?: Record<string, unknown>;
56
83
  /** State from previous setup or iterate call */
57
84
  state?: Record<string, unknown>;
85
+ /**
86
+ * Merged environment (process.env + baked MCP_ENV + request env),
87
+ * same layering as tool handlers via buildToolExecutionEnv.
88
+ */
89
+ env: Record<string, string>;
90
+ /** Invocation context for log traceability */
91
+ invocation?: InvocationContext;
58
92
  /** Logger instance */
59
93
  log: {
60
94
  info: (message: string, meta?: Record<string, unknown>) => void;
@@ -65,7 +99,7 @@ export interface BatchOperationContext {
65
99
  /**
66
100
  * Type for batch operation setup function.
67
101
  */
68
- export type BatchOperationSetupFn = (ctx: BatchOperationContext) => Promise<BatchOperationSetupResult>;
102
+ export type BatchOperationSetupFn = (ctx: BatchOperationContext) => Promise<BatchOperationSetupReturn>;
69
103
  /**
70
104
  * Type for batch operation iterate function.
71
105
  */
@@ -76,7 +110,7 @@ export type BatchOperationIterateFn = (ctx: BatchOperationContext & {
76
110
  cursor?: string | number;
77
111
  /** Items per page */
78
112
  limit: number;
79
- }) => Promise<BatchOperationIterateResult>;
113
+ }) => Promise<BatchOperationIterateReturn>;
80
114
  /**
81
115
  * Batch operation definition.
82
116
  *
@@ -90,7 +124,9 @@ export type BatchOperationIterateFn = (ctx: BatchOperationContext & {
90
124
  * return { total: count }
91
125
  * },
92
126
  * iterate: async (ctx) => {
127
+ * const apiKey = ctx.env.GLOFOX_API_KEY
93
128
  * const { data, pagination } = await glofox.getMembers({
129
+ * apiKey,
94
130
  * limit: ctx.limit,
95
131
  * offset: ctx.cursor ?? 0,
96
132
  * })
@@ -1988,6 +1988,39 @@ async function handleMcpBatchRoute(req, ctx) {
1988
1988
  }
1989
1989
  };
1990
1990
  }
1991
+ function isBatchOperationFailure(result) {
1992
+ return result != null && typeof result === "object" && result.success === false && typeof result.error === "object" && result.error != null;
1993
+ }
1994
+ function toStringEnv(env) {
1995
+ const out = {};
1996
+ for (const [key, value] of Object.entries(env)) {
1997
+ if (value !== void 0) {
1998
+ out[key] = value;
1999
+ }
2000
+ }
2001
+ return out;
2002
+ }
2003
+ function stripBillingFields(result) {
2004
+ const {
2005
+ billing: _billing,
2006
+ success: _success,
2007
+ error: _error,
2008
+ retry: _retry,
2009
+ ...domain
2010
+ } = result;
2011
+ return domain;
2012
+ }
2013
+ function softFailureResponse(error, retry, billing) {
2014
+ return {
2015
+ status: 200,
2016
+ body: {
2017
+ success: false,
2018
+ error,
2019
+ ...retry ? { retry } : {},
2020
+ billing: normalizeBilling(billing)
2021
+ }
2022
+ };
2023
+ }
1991
2024
  async function handleBatchOperationRoute(req, ctx) {
1992
2025
  const bodyResult = parseJsonBody(req);
1993
2026
  if (!bodyResult.success) {
@@ -1996,34 +2029,80 @@ async function handleBatchOperationRoute(req, ctx) {
1996
2029
  const body = bodyResult.data;
1997
2030
  const registry = ctx.batchOperationRegistry;
1998
2031
  if (!registry) {
1999
- return {
2000
- status: 404,
2001
- body: {
2002
- success: false,
2003
- error: "No batch operations registered"
2004
- }
2005
- };
2032
+ return softFailureResponse({
2033
+ code: "NOT_FOUND",
2034
+ message: "No batch operations registered",
2035
+ category: "validation"
2036
+ });
2006
2037
  }
2007
2038
  const operation = registry[body.handle];
2008
2039
  if (!operation) {
2009
- return {
2010
- status: 404,
2011
- body: {
2012
- success: false,
2013
- error: `Batch operation not found: ${body.handle}`
2014
- }
2015
- };
2040
+ return softFailureResponse({
2041
+ code: "NOT_FOUND",
2042
+ message: `Batch operation not found: ${body.handle}`,
2043
+ category: "validation"
2044
+ });
2016
2045
  }
2017
- const log = {
2018
- info: (message, meta) => {
2019
- console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
2020
- },
2021
- warn: (message, meta) => {
2022
- console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
2023
- },
2024
- error: (message, meta) => {
2025
- console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
2026
- }
2046
+ const context = body.context;
2047
+ if (!context?.workplaceId || !context?.appInstallationId || !context?.appId) {
2048
+ return softFailureResponse({
2049
+ code: "VALIDATION_ERROR",
2050
+ message: "Missing context (workplaceId, appInstallationId, and appId required)",
2051
+ category: "validation"
2052
+ });
2053
+ }
2054
+ if (body.method !== "setup" && body.method !== "iterate") {
2055
+ return softFailureResponse({
2056
+ code: "VALIDATION_ERROR",
2057
+ message: `Unknown method: ${body.method}`,
2058
+ category: "validation"
2059
+ });
2060
+ }
2061
+ const requestEnv = body.env ?? {};
2062
+ const mergedEnv = toStringEnv(buildToolExecutionEnv(requestEnv));
2063
+ const originalEnv = { ...process.env };
2064
+ Object.assign(process.env, mergedEnv);
2065
+ const log = createContextLogger();
2066
+ const app = context.app ?? {
2067
+ id: context.appId,
2068
+ versionId: context.appId
2069
+ };
2070
+ const workplace = context.workplace ?? {
2071
+ id: context.workplaceId,
2072
+ subdomain: ""
2073
+ };
2074
+ const invocation = body.invocation ?? {
2075
+ invocationId: `${body.handle}-${body.method}-${Date.now()}`,
2076
+ invocationType: "batch_operation",
2077
+ batchOperationHandle: body.handle,
2078
+ batchOperationMethod: body.method,
2079
+ appInstallationId: context.appInstallationId
2080
+ };
2081
+ const requestConfig = {
2082
+ baseUrl: mergedEnv.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? "",
2083
+ apiToken: mergedEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? ""
2084
+ };
2085
+ const rateLimitContext = {
2086
+ app,
2087
+ appInstallationId: context.appInstallationId,
2088
+ invocation,
2089
+ preAcquiredLeases: parsePreAcquiredLeases(
2090
+ mergedEnv.SKEDYUL_RATE_LIMIT_LEASES
2091
+ ),
2092
+ heldMutexQueueKeys: parseHeldMutexQueueKeys(
2093
+ mergedEnv.SKEDYUL_HELD_MUTEX_QUEUE_KEYS
2094
+ )
2095
+ };
2096
+ const opContextBase = {
2097
+ workplaceId: context.workplaceId,
2098
+ appInstallationId: context.appInstallationId,
2099
+ appId: context.appId,
2100
+ app,
2101
+ workplace,
2102
+ input: body.input,
2103
+ env: mergedEnv,
2104
+ invocation,
2105
+ log
2027
2106
  };
2028
2107
  try {
2029
2108
  if (body.method === "setup") {
@@ -2032,61 +2111,88 @@ async function handleBatchOperationRoute(req, ctx) {
2032
2111
  status: 200,
2033
2112
  body: {
2034
2113
  success: true,
2035
- result: { state: {}, total: void 0 }
2114
+ result: { state: {}, total: void 0 },
2115
+ billing: normalizeBilling(void 0)
2036
2116
  }
2037
2117
  };
2038
2118
  }
2039
- const result = await operation.setup({
2040
- workplaceId: body.workplaceId,
2041
- appInstallationId: body.appInstallationId,
2042
- appId: body.appId,
2043
- input: body.input,
2044
- log
2119
+ const raw2 = await runWithConfig(requestConfig, async () => {
2120
+ return runWithRateLimitExecutionContext(rateLimitContext, async () => {
2121
+ return runWithLogContext({ invocation }, async () => {
2122
+ return operation.setup(opContextBase);
2123
+ });
2124
+ });
2045
2125
  });
2126
+ if (isBatchOperationFailure(raw2)) {
2127
+ return softFailureResponse(raw2.error, raw2.retry, raw2.billing);
2128
+ }
2129
+ const setupResult = raw2;
2130
+ const domain2 = stripBillingFields(
2131
+ setupResult
2132
+ );
2046
2133
  return {
2047
2134
  status: 200,
2048
2135
  body: {
2049
2136
  success: true,
2050
- result
2137
+ result: domain2,
2138
+ billing: normalizeBilling(setupResult.billing)
2051
2139
  }
2052
2140
  };
2053
2141
  }
2054
- if (body.method === "iterate") {
2055
- const result = await operation.iterate({
2056
- workplaceId: body.workplaceId,
2057
- appInstallationId: body.appInstallationId,
2058
- appId: body.appId,
2059
- input: body.input,
2060
- state: body.state,
2061
- page: body.page,
2062
- cursor: body.cursor,
2063
- limit: body.limit,
2064
- log
2142
+ const raw = await runWithConfig(requestConfig, async () => {
2143
+ return runWithRateLimitExecutionContext(rateLimitContext, async () => {
2144
+ return runWithLogContext({ invocation }, async () => {
2145
+ return operation.iterate({
2146
+ ...opContextBase,
2147
+ state: body.state,
2148
+ page: body.page,
2149
+ cursor: body.cursor,
2150
+ limit: body.limit
2151
+ });
2152
+ });
2065
2153
  });
2066
- return {
2067
- status: 200,
2068
- body: {
2069
- success: true,
2070
- result
2071
- }
2072
- };
2154
+ });
2155
+ if (isBatchOperationFailure(raw)) {
2156
+ return softFailureResponse(raw.error, raw.retry, raw.billing);
2073
2157
  }
2158
+ const iterateResult = raw;
2159
+ const domain = stripBillingFields(
2160
+ iterateResult
2161
+ );
2074
2162
  return {
2075
- status: 400,
2163
+ status: 200,
2076
2164
  body: {
2077
- success: false,
2078
- error: `Unknown method: ${body.method}`
2165
+ success: true,
2166
+ result: domain,
2167
+ billing: normalizeBilling(iterateResult.billing)
2079
2168
  }
2080
2169
  };
2081
2170
  } catch (err) {
2082
- log.error("Batch operation failed", { error: err });
2171
+ if (err instanceof RateLimitExceededError) {
2172
+ return softFailureResponse(
2173
+ {
2174
+ code: "RATE_LIMITED",
2175
+ message: err.message,
2176
+ category: "external"
2177
+ },
2178
+ { allowed: true, afterMs: err.retryAfterMs }
2179
+ );
2180
+ }
2181
+ log.error("Batch operation failed", err);
2083
2182
  return {
2084
2183
  status: 500,
2085
2184
  body: {
2086
2185
  success: false,
2087
- error: err instanceof Error ? err.message : String(err)
2186
+ error: {
2187
+ code: "INTERNAL_ERROR",
2188
+ message: err instanceof Error ? err.message : String(err),
2189
+ category: "internal"
2190
+ },
2191
+ billing: normalizeBilling(void 0)
2088
2192
  }
2089
2193
  };
2194
+ } finally {
2195
+ process.env = originalEnv;
2090
2196
  }
2091
2197
  }
2092
2198
  function createNotFoundResponse() {