skedyul 1.7.5 → 1.7.7

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.
@@ -1901,6 +1901,31 @@ var SetupStepDefinitionSchema = z8.object({
1901
1901
  listenToEnv: z8.boolean().optional(),
1902
1902
  capabilities: z8.array(z8.string()).optional()
1903
1903
  });
1904
+ var BatchPaginationSchema = z8.object({
1905
+ hasMore: z8.boolean(),
1906
+ page: z8.number().int().optional(),
1907
+ total: z8.number().int().optional(),
1908
+ nextCursor: z8.union([z8.string(), z8.number()]).optional(),
1909
+ limit: z8.number().int().positive().optional()
1910
+ });
1911
+ var BatchOperationSetupResultSchema = z8.object({
1912
+ state: z8.record(z8.string(), z8.unknown()).optional(),
1913
+ total: z8.number().int().nonnegative().optional()
1914
+ });
1915
+ var BatchOperationIterateResultSchema = z8.object({
1916
+ items: z8.array(z8.record(z8.string(), z8.unknown())),
1917
+ pagination: BatchPaginationSchema,
1918
+ state: z8.record(z8.string(), z8.unknown()).optional()
1919
+ });
1920
+ var BatchOperationDefinitionSchema = z8.object({
1921
+ handle: z8.string(),
1922
+ label: z8.string(),
1923
+ description: z8.string().optional(),
1924
+ entity: z8.string(),
1925
+ maxConcurrent: z8.number().int().positive().optional(),
1926
+ pageSize: z8.number().int().positive().optional(),
1927
+ icon: z8.string().optional()
1928
+ });
1904
1929
  var ProvisionConfigSchema = z8.object({
1905
1930
  env: EnvSchemaSchema.optional(),
1906
1931
  /** INTERNAL model definitions (app-owned, not visible to users) */
@@ -1915,7 +1940,9 @@ var ProvisionConfigSchema = z8.object({
1915
1940
  navigation: NavigationConfigSchema.optional(),
1916
1941
  pages: z8.array(PageDefinitionSchema).optional(),
1917
1942
  /** Install setup checklist steps (opt-in) */
1918
- setup: z8.array(SetupStepDefinitionSchema).optional()
1943
+ setup: z8.array(SetupStepDefinitionSchema).optional(),
1944
+ /** Batch operations for imports, syncs, and long-running tasks */
1945
+ batchOperations: z8.array(BatchOperationDefinitionSchema).optional()
1919
1946
  });
1920
1947
  var SkedyulConfigSchema = z8.object({
1921
1948
  name: z8.string(),
@@ -5437,6 +5464,107 @@ async function handleMcpBatchRoute(req, ctx) {
5437
5464
  }
5438
5465
  };
5439
5466
  }
5467
+ async function handleBatchOperationRoute(req, ctx) {
5468
+ const bodyResult = parseJsonBody(req);
5469
+ if (!bodyResult.success) {
5470
+ return bodyResult.error;
5471
+ }
5472
+ const body = bodyResult.data;
5473
+ const registry = ctx.batchOperationRegistry;
5474
+ if (!registry) {
5475
+ return {
5476
+ status: 404,
5477
+ body: {
5478
+ success: false,
5479
+ error: "No batch operations registered"
5480
+ }
5481
+ };
5482
+ }
5483
+ const operation = registry[body.handle];
5484
+ if (!operation) {
5485
+ return {
5486
+ status: 404,
5487
+ body: {
5488
+ success: false,
5489
+ error: `Batch operation not found: ${body.handle}`
5490
+ }
5491
+ };
5492
+ }
5493
+ const log = {
5494
+ info: (message, meta) => {
5495
+ console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
5496
+ },
5497
+ warn: (message, meta) => {
5498
+ console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
5499
+ },
5500
+ error: (message, meta) => {
5501
+ console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
5502
+ }
5503
+ };
5504
+ try {
5505
+ if (body.method === "setup") {
5506
+ if (!operation.setup) {
5507
+ return {
5508
+ status: 200,
5509
+ body: {
5510
+ success: true,
5511
+ result: { state: {}, total: void 0 }
5512
+ }
5513
+ };
5514
+ }
5515
+ const result = await operation.setup({
5516
+ workplaceId: body.workplaceId,
5517
+ appInstallationId: body.appInstallationId,
5518
+ appId: body.appId,
5519
+ input: body.input,
5520
+ log
5521
+ });
5522
+ return {
5523
+ status: 200,
5524
+ body: {
5525
+ success: true,
5526
+ result
5527
+ }
5528
+ };
5529
+ }
5530
+ if (body.method === "iterate") {
5531
+ const result = await operation.iterate({
5532
+ workplaceId: body.workplaceId,
5533
+ appInstallationId: body.appInstallationId,
5534
+ appId: body.appId,
5535
+ input: body.input,
5536
+ state: body.state,
5537
+ page: body.page,
5538
+ cursor: body.cursor,
5539
+ limit: body.limit,
5540
+ log
5541
+ });
5542
+ return {
5543
+ status: 200,
5544
+ body: {
5545
+ success: true,
5546
+ result
5547
+ }
5548
+ };
5549
+ }
5550
+ return {
5551
+ status: 400,
5552
+ body: {
5553
+ success: false,
5554
+ error: `Unknown method: ${body.method}`
5555
+ }
5556
+ };
5557
+ } catch (err) {
5558
+ log.error("Batch operation failed", { error: err });
5559
+ return {
5560
+ status: 500,
5561
+ body: {
5562
+ success: false,
5563
+ error: err instanceof Error ? err.message : String(err)
5564
+ }
5565
+ };
5566
+ }
5567
+ }
5440
5568
  function createNotFoundResponse() {
5441
5569
  return {
5442
5570
  status: 404,
@@ -5516,6 +5644,9 @@ async function routeRequest(req, ctx) {
5516
5644
  if (req.path === "/mcp/batch" && req.method === "POST") {
5517
5645
  return handleMcpBatchRoute(req, ctx);
5518
5646
  }
5647
+ if (req.path === "/batch-operation" && req.method === "POST") {
5648
+ return handleBatchOperationRoute(req, ctx);
5649
+ }
5519
5650
  return createNotFoundResponse();
5520
5651
  } catch (err) {
5521
5652
  return createErrorResponse2(err);
@@ -5557,11 +5688,13 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
5557
5688
  const defaultHeaders = getDefaultHeaders(config.cors);
5558
5689
  const registry = config.tools;
5559
5690
  const webhookRegistry = config.webhooks;
5691
+ const batchOperationRegistry = config.batchOperations;
5560
5692
  const ctx = {
5561
5693
  config,
5562
5694
  tools,
5563
5695
  registry,
5564
5696
  webhookRegistry,
5697
+ batchOperationRegistry,
5565
5698
  callTool,
5566
5699
  state,
5567
5700
  mcpServer,
@@ -5676,12 +5809,14 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
5676
5809
  const defaultHeaders = getDefaultHeaders(config.cors);
5677
5810
  const registry = config.tools;
5678
5811
  const webhookRegistry = config.webhooks;
5812
+ const batchOperationRegistry = config.batchOperations;
5679
5813
  let hasLoggedStartup = false;
5680
5814
  const ctx = {
5681
5815
  config,
5682
5816
  tools,
5683
5817
  registry,
5684
5818
  webhookRegistry,
5819
+ batchOperationRegistry,
5685
5820
  callTool,
5686
5821
  state,
5687
5822
  mcpServer,
@@ -5979,6 +6114,9 @@ function defineNavigation(navigation) {
5979
6114
  function defineSetupStep(step) {
5980
6115
  return step;
5981
6116
  }
6117
+ function defineBatchOperation(operation) {
6118
+ return operation;
6119
+ }
5982
6120
 
5983
6121
  // src/config/schema-loader.ts
5984
6122
  import * as fs4 from "fs";
@@ -8027,7 +8165,15 @@ var WaitInputRelativeSchema = z15.object({
8027
8165
  mode: z15.literal("relative"),
8028
8166
  amount: z15.number(),
8029
8167
  unit: WaitUnitSchema,
8030
- windows: z15.array(TimeWindowSlotSchema).optional()
8168
+ windows: z15.array(TimeWindowSlotSchema).optional(),
8169
+ /**
8170
+ * Optional ISO datetime to use as the base for the relative delay instead of
8171
+ * wall-clock `now`. Used for cadence chaining (schedule relative to a prior
8172
+ * message's scheduledAt). `waitTime` is still measured from wall-clock `now`.
8173
+ */
8174
+ from: z15.union([z15.string(), z15.date()]).optional().describe(
8175
+ "ISO datetime base for the relative delay (e.g. previous message scheduledAt)"
8176
+ )
8031
8177
  });
8032
8178
  var WaitInputAbsoluteSchema = z15.object({
8033
8179
  mode: z15.literal("absolute"),
@@ -8140,10 +8286,12 @@ function calculateWaitTime(step, now) {
8140
8286
  };
8141
8287
  }
8142
8288
  case "relative": {
8289
+ const baseTime = step.from != null ? new Date(step.from).getTime() : nowTime;
8290
+ const baseDate = new Date(baseTime);
8143
8291
  if (!step.amount && (!step.windows || step.windows.length === 0)) {
8144
8292
  return {
8145
- waitTime: 0,
8146
- scheduledAt: now
8293
+ waitTime: Math.max(0, baseTime - nowTime),
8294
+ scheduledAt: baseDate
8147
8295
  };
8148
8296
  }
8149
8297
  let relativeDelay = 0;
@@ -8182,17 +8330,18 @@ function calculateWaitTime(step, now) {
8182
8330
  }
8183
8331
  }
8184
8332
  if (!step.windows || step.windows.length === 0) {
8333
+ const scheduledAt = new Date(baseTime + relativeDelay);
8185
8334
  return {
8186
- waitTime: relativeDelay,
8187
- scheduledAt: new Date(nowTime + relativeDelay)
8335
+ waitTime: Math.max(0, scheduledAt.getTime() - nowTime),
8336
+ scheduledAt
8188
8337
  };
8189
8338
  }
8190
- const targetDate = new Date(nowTime + relativeDelay);
8339
+ const targetDate = new Date(baseTime + relativeDelay);
8191
8340
  for (const window of step.windows) {
8192
8341
  if (isTimeInWindowSlot(targetDate, window)) {
8193
8342
  return {
8194
- waitTime: relativeDelay,
8195
- scheduledAt: new Date(nowTime + relativeDelay)
8343
+ waitTime: Math.max(0, targetDate.getTime() - nowTime),
8344
+ scheduledAt: targetDate
8196
8345
  };
8197
8346
  }
8198
8347
  }
@@ -8237,8 +8386,8 @@ function calculateWaitTime(step, now) {
8237
8386
  msUntilWindowStart = daysMs + hoursAdjustment + minutesAdjustment;
8238
8387
  }
8239
8388
  const windowStartTimeMs = targetDate.getTime() + msUntilWindowStart;
8240
- const sameLocalDayAsNow = getLocalDateKey(now, tz) === getLocalDateKey(targetDate, tz);
8241
- const windowScheduledTime = sameLocalDayAsNow ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
8389
+ const sameLocalDayAsBase = getLocalDateKey(baseDate, tz) === getLocalDateKey(targetDate, tz);
8390
+ const windowScheduledTime = sameLocalDayAsBase ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
8242
8391
  const waitFromNow = windowScheduledTime.getTime() - nowTime;
8243
8392
  if (waitFromNow < earliestWaitFromNow) {
8244
8393
  earliestWaitFromNow = waitFromNow;
@@ -8412,6 +8561,10 @@ export {
8412
8561
  AssociationSchema,
8413
8562
  AuthenticationError,
8414
8563
  BaseEventPayloadSchema,
8564
+ BatchOperationDefinitionSchema,
8565
+ BatchOperationIterateResultSchema,
8566
+ BatchOperationSetupResultSchema,
8567
+ BatchPaginationSchema,
8415
8568
  BreadcrumbItemSchema,
8416
8569
  CRMCardinalitySchema,
8417
8570
  CRMContextSchema2 as CRMContextSchema,
@@ -8664,6 +8817,7 @@ export {
8664
8817
  src_default as default,
8665
8818
  defaultShouldRetry,
8666
8819
  defineAgent,
8820
+ defineBatchOperation,
8667
8821
  defineChannel,
8668
8822
  defineConfig,
8669
8823
  defineEntity,
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ declare const _default: {
16
16
  z: typeof z;
17
17
  };
18
18
  export default _default;
19
- export { defineConfig, defineModel, defineEntity, defineChannel, definePage, defineWorkflow, defineAgent, defineEnv, defineNavigation, defineSetupStep, getAllEnvKeys, getRequiredInstallEnvKeys, } from './config';
19
+ export { defineConfig, defineModel, defineEntity, defineChannel, definePage, defineWorkflow, defineAgent, defineEnv, defineNavigation, defineSetupStep, defineBatchOperation, getAllEnvKeys, getRequiredInstallEnvKeys, } from './config';
20
20
  export { queuedFetch, requeue, resolveQueue, createQueueHandle, queuedFetchResponse, registerQueueConfig, runWithRateLimitExecutionContext, getRateLimitExecutionContext, defaultShouldRetry, QueueContextError, QueueNotFoundError, QueuedFetchExhaustedError, RequeueOutsideContextError, RateLimitBackendError, RateLimitExceededError, } from './ratelimit';
21
21
  export type { QueueInput, QueueSelector, Lease, QueueLimits, ResolvedQueue, RateLimitExecutionContext, RateLimitBackend, QueueScope, QueueConfig, SerializableQueueConfig, QueueRegistry, } from './ratelimit';
22
22
  export { sequencer, allow as sequencerAllow, acquire as sequencerAcquire, release as sequencerRelease, resolveSequencer, createSequencerHandle, registerSequencerConfig, clearRegisteredSequencerConfig, getSequencerConfig, getSequencerDefinitions, resetSequencerBackendForTests, memorySequencerBackend, platformSequencerBackend, SequencerContextError, SequencerNotFoundError, SequencerBackendError, SequencerLockError, } from './sequencer';
package/dist/index.js CHANGED
@@ -42,6 +42,10 @@ __export(index_exports, {
42
42
  AssociationSchema: () => AssociationSchema,
43
43
  AuthenticationError: () => AuthenticationError,
44
44
  BaseEventPayloadSchema: () => BaseEventPayloadSchema,
45
+ BatchOperationDefinitionSchema: () => BatchOperationDefinitionSchema,
46
+ BatchOperationIterateResultSchema: () => BatchOperationIterateResultSchema,
47
+ BatchOperationSetupResultSchema: () => BatchOperationSetupResultSchema,
48
+ BatchPaginationSchema: () => BatchPaginationSchema,
45
49
  BreadcrumbItemSchema: () => BreadcrumbItemSchema,
46
50
  CRMCardinalitySchema: () => CRMCardinalitySchema,
47
51
  CRMContextSchema: () => CRMContextSchema2,
@@ -294,6 +298,7 @@ __export(index_exports, {
294
298
  default: () => index_default,
295
299
  defaultShouldRetry: () => defaultShouldRetry,
296
300
  defineAgent: () => defineAgent,
301
+ defineBatchOperation: () => defineBatchOperation,
297
302
  defineChannel: () => defineChannel,
298
303
  defineConfig: () => defineConfig,
299
304
  defineEntity: () => defineEntity,
@@ -2275,6 +2280,31 @@ var SetupStepDefinitionSchema = import_v48.z.object({
2275
2280
  listenToEnv: import_v48.z.boolean().optional(),
2276
2281
  capabilities: import_v48.z.array(import_v48.z.string()).optional()
2277
2282
  });
2283
+ var BatchPaginationSchema = import_v48.z.object({
2284
+ hasMore: import_v48.z.boolean(),
2285
+ page: import_v48.z.number().int().optional(),
2286
+ total: import_v48.z.number().int().optional(),
2287
+ nextCursor: import_v48.z.union([import_v48.z.string(), import_v48.z.number()]).optional(),
2288
+ limit: import_v48.z.number().int().positive().optional()
2289
+ });
2290
+ var BatchOperationSetupResultSchema = import_v48.z.object({
2291
+ state: import_v48.z.record(import_v48.z.string(), import_v48.z.unknown()).optional(),
2292
+ total: import_v48.z.number().int().nonnegative().optional()
2293
+ });
2294
+ var BatchOperationIterateResultSchema = import_v48.z.object({
2295
+ items: import_v48.z.array(import_v48.z.record(import_v48.z.string(), import_v48.z.unknown())),
2296
+ pagination: BatchPaginationSchema,
2297
+ state: import_v48.z.record(import_v48.z.string(), import_v48.z.unknown()).optional()
2298
+ });
2299
+ var BatchOperationDefinitionSchema = import_v48.z.object({
2300
+ handle: import_v48.z.string(),
2301
+ label: import_v48.z.string(),
2302
+ description: import_v48.z.string().optional(),
2303
+ entity: import_v48.z.string(),
2304
+ maxConcurrent: import_v48.z.number().int().positive().optional(),
2305
+ pageSize: import_v48.z.number().int().positive().optional(),
2306
+ icon: import_v48.z.string().optional()
2307
+ });
2278
2308
  var ProvisionConfigSchema = import_v48.z.object({
2279
2309
  env: EnvSchemaSchema.optional(),
2280
2310
  /** INTERNAL model definitions (app-owned, not visible to users) */
@@ -2289,7 +2319,9 @@ var ProvisionConfigSchema = import_v48.z.object({
2289
2319
  navigation: NavigationConfigSchema.optional(),
2290
2320
  pages: import_v48.z.array(PageDefinitionSchema).optional(),
2291
2321
  /** Install setup checklist steps (opt-in) */
2292
- setup: import_v48.z.array(SetupStepDefinitionSchema).optional()
2322
+ setup: import_v48.z.array(SetupStepDefinitionSchema).optional(),
2323
+ /** Batch operations for imports, syncs, and long-running tasks */
2324
+ batchOperations: import_v48.z.array(BatchOperationDefinitionSchema).optional()
2293
2325
  });
2294
2326
  var SkedyulConfigSchema = import_v48.z.object({
2295
2327
  name: import_v48.z.string(),
@@ -5811,6 +5843,107 @@ async function handleMcpBatchRoute(req, ctx) {
5811
5843
  }
5812
5844
  };
5813
5845
  }
5846
+ async function handleBatchOperationRoute(req, ctx) {
5847
+ const bodyResult = parseJsonBody(req);
5848
+ if (!bodyResult.success) {
5849
+ return bodyResult.error;
5850
+ }
5851
+ const body = bodyResult.data;
5852
+ const registry = ctx.batchOperationRegistry;
5853
+ if (!registry) {
5854
+ return {
5855
+ status: 404,
5856
+ body: {
5857
+ success: false,
5858
+ error: "No batch operations registered"
5859
+ }
5860
+ };
5861
+ }
5862
+ const operation = registry[body.handle];
5863
+ if (!operation) {
5864
+ return {
5865
+ status: 404,
5866
+ body: {
5867
+ success: false,
5868
+ error: `Batch operation not found: ${body.handle}`
5869
+ }
5870
+ };
5871
+ }
5872
+ const log = {
5873
+ info: (message, meta) => {
5874
+ console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
5875
+ },
5876
+ warn: (message, meta) => {
5877
+ console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
5878
+ },
5879
+ error: (message, meta) => {
5880
+ console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
5881
+ }
5882
+ };
5883
+ try {
5884
+ if (body.method === "setup") {
5885
+ if (!operation.setup) {
5886
+ return {
5887
+ status: 200,
5888
+ body: {
5889
+ success: true,
5890
+ result: { state: {}, total: void 0 }
5891
+ }
5892
+ };
5893
+ }
5894
+ const result = await operation.setup({
5895
+ workplaceId: body.workplaceId,
5896
+ appInstallationId: body.appInstallationId,
5897
+ appId: body.appId,
5898
+ input: body.input,
5899
+ log
5900
+ });
5901
+ return {
5902
+ status: 200,
5903
+ body: {
5904
+ success: true,
5905
+ result
5906
+ }
5907
+ };
5908
+ }
5909
+ if (body.method === "iterate") {
5910
+ const result = await operation.iterate({
5911
+ workplaceId: body.workplaceId,
5912
+ appInstallationId: body.appInstallationId,
5913
+ appId: body.appId,
5914
+ input: body.input,
5915
+ state: body.state,
5916
+ page: body.page,
5917
+ cursor: body.cursor,
5918
+ limit: body.limit,
5919
+ log
5920
+ });
5921
+ return {
5922
+ status: 200,
5923
+ body: {
5924
+ success: true,
5925
+ result
5926
+ }
5927
+ };
5928
+ }
5929
+ return {
5930
+ status: 400,
5931
+ body: {
5932
+ success: false,
5933
+ error: `Unknown method: ${body.method}`
5934
+ }
5935
+ };
5936
+ } catch (err) {
5937
+ log.error("Batch operation failed", { error: err });
5938
+ return {
5939
+ status: 500,
5940
+ body: {
5941
+ success: false,
5942
+ error: err instanceof Error ? err.message : String(err)
5943
+ }
5944
+ };
5945
+ }
5946
+ }
5814
5947
  function createNotFoundResponse() {
5815
5948
  return {
5816
5949
  status: 404,
@@ -5890,6 +6023,9 @@ async function routeRequest(req, ctx) {
5890
6023
  if (req.path === "/mcp/batch" && req.method === "POST") {
5891
6024
  return handleMcpBatchRoute(req, ctx);
5892
6025
  }
6026
+ if (req.path === "/batch-operation" && req.method === "POST") {
6027
+ return handleBatchOperationRoute(req, ctx);
6028
+ }
5893
6029
  return createNotFoundResponse();
5894
6030
  } catch (err) {
5895
6031
  return createErrorResponse2(err);
@@ -5931,11 +6067,13 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
5931
6067
  const defaultHeaders = getDefaultHeaders(config.cors);
5932
6068
  const registry = config.tools;
5933
6069
  const webhookRegistry = config.webhooks;
6070
+ const batchOperationRegistry = config.batchOperations;
5934
6071
  const ctx = {
5935
6072
  config,
5936
6073
  tools,
5937
6074
  registry,
5938
6075
  webhookRegistry,
6076
+ batchOperationRegistry,
5939
6077
  callTool,
5940
6078
  state,
5941
6079
  mcpServer,
@@ -6050,12 +6188,14 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
6050
6188
  const defaultHeaders = getDefaultHeaders(config.cors);
6051
6189
  const registry = config.tools;
6052
6190
  const webhookRegistry = config.webhooks;
6191
+ const batchOperationRegistry = config.batchOperations;
6053
6192
  let hasLoggedStartup = false;
6054
6193
  const ctx = {
6055
6194
  config,
6056
6195
  tools,
6057
6196
  registry,
6058
6197
  webhookRegistry,
6198
+ batchOperationRegistry,
6059
6199
  callTool,
6060
6200
  state,
6061
6201
  mcpServer,
@@ -6353,6 +6493,9 @@ function defineNavigation(navigation) {
6353
6493
  function defineSetupStep(step) {
6354
6494
  return step;
6355
6495
  }
6496
+ function defineBatchOperation(operation) {
6497
+ return operation;
6498
+ }
6356
6499
 
6357
6500
  // src/config/schema-loader.ts
6358
6501
  var fs4 = __toESM(require("fs"));
@@ -8401,7 +8544,15 @@ var WaitInputRelativeSchema = import_v413.z.object({
8401
8544
  mode: import_v413.z.literal("relative"),
8402
8545
  amount: import_v413.z.number(),
8403
8546
  unit: WaitUnitSchema,
8404
- windows: import_v413.z.array(TimeWindowSlotSchema).optional()
8547
+ windows: import_v413.z.array(TimeWindowSlotSchema).optional(),
8548
+ /**
8549
+ * Optional ISO datetime to use as the base for the relative delay instead of
8550
+ * wall-clock `now`. Used for cadence chaining (schedule relative to a prior
8551
+ * message's scheduledAt). `waitTime` is still measured from wall-clock `now`.
8552
+ */
8553
+ from: import_v413.z.union([import_v413.z.string(), import_v413.z.date()]).optional().describe(
8554
+ "ISO datetime base for the relative delay (e.g. previous message scheduledAt)"
8555
+ )
8405
8556
  });
8406
8557
  var WaitInputAbsoluteSchema = import_v413.z.object({
8407
8558
  mode: import_v413.z.literal("absolute"),
@@ -8514,10 +8665,12 @@ function calculateWaitTime(step, now) {
8514
8665
  };
8515
8666
  }
8516
8667
  case "relative": {
8668
+ const baseTime = step.from != null ? new Date(step.from).getTime() : nowTime;
8669
+ const baseDate = new Date(baseTime);
8517
8670
  if (!step.amount && (!step.windows || step.windows.length === 0)) {
8518
8671
  return {
8519
- waitTime: 0,
8520
- scheduledAt: now
8672
+ waitTime: Math.max(0, baseTime - nowTime),
8673
+ scheduledAt: baseDate
8521
8674
  };
8522
8675
  }
8523
8676
  let relativeDelay = 0;
@@ -8556,17 +8709,18 @@ function calculateWaitTime(step, now) {
8556
8709
  }
8557
8710
  }
8558
8711
  if (!step.windows || step.windows.length === 0) {
8712
+ const scheduledAt = new Date(baseTime + relativeDelay);
8559
8713
  return {
8560
- waitTime: relativeDelay,
8561
- scheduledAt: new Date(nowTime + relativeDelay)
8714
+ waitTime: Math.max(0, scheduledAt.getTime() - nowTime),
8715
+ scheduledAt
8562
8716
  };
8563
8717
  }
8564
- const targetDate = new Date(nowTime + relativeDelay);
8718
+ const targetDate = new Date(baseTime + relativeDelay);
8565
8719
  for (const window of step.windows) {
8566
8720
  if (isTimeInWindowSlot(targetDate, window)) {
8567
8721
  return {
8568
- waitTime: relativeDelay,
8569
- scheduledAt: new Date(nowTime + relativeDelay)
8722
+ waitTime: Math.max(0, targetDate.getTime() - nowTime),
8723
+ scheduledAt: targetDate
8570
8724
  };
8571
8725
  }
8572
8726
  }
@@ -8611,8 +8765,8 @@ function calculateWaitTime(step, now) {
8611
8765
  msUntilWindowStart = daysMs + hoursAdjustment + minutesAdjustment;
8612
8766
  }
8613
8767
  const windowStartTimeMs = targetDate.getTime() + msUntilWindowStart;
8614
- const sameLocalDayAsNow = getLocalDateKey(now, tz) === getLocalDateKey(targetDate, tz);
8615
- const windowScheduledTime = sameLocalDayAsNow ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
8768
+ const sameLocalDayAsBase = getLocalDateKey(baseDate, tz) === getLocalDateKey(targetDate, tz);
8769
+ const windowScheduledTime = sameLocalDayAsBase ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
8616
8770
  const waitFromNow = windowScheduledTime.getTime() - nowTime;
8617
8771
  if (waitFromNow < earliestWaitFromNow) {
8618
8772
  earliestWaitFromNow = waitFromNow;
@@ -8787,6 +8941,10 @@ var index_default = { z: import_v414.z };
8787
8941
  AssociationSchema,
8788
8942
  AuthenticationError,
8789
8943
  BaseEventPayloadSchema,
8944
+ BatchOperationDefinitionSchema,
8945
+ BatchOperationIterateResultSchema,
8946
+ BatchOperationSetupResultSchema,
8947
+ BatchPaginationSchema,
8790
8948
  BreadcrumbItemSchema,
8791
8949
  CRMCardinalitySchema,
8792
8950
  CRMContextSchema,
@@ -9038,6 +9196,7 @@ var index_default = { z: import_v414.z };
9038
9196
  cron,
9039
9197
  defaultShouldRetry,
9040
9198
  defineAgent,
9199
+ defineBatchOperation,
9041
9200
  defineChannel,
9042
9201
  defineConfig,
9043
9202
  defineEntity,
@@ -9,8 +9,10 @@
9
9
  import type { WaitInputType, CalculateWaitTimeResult } from './types-workflow';
10
10
  /**
11
11
  * Calculate the wait time for a wait step
12
- * @param step The input parameters for the wait step
13
- * @param now The current date/time
12
+ * @param step The input parameters for the wait step. Relative mode may include
13
+ * optional `from` (ISO datetime / Date) as the base for the delay instead of `now`.
14
+ * @param now Wall-clock current date/time. Used as the default relative base and
15
+ * always used to compute `waitTime` (ms until `scheduledAt`).
14
16
  * @returns The time to wait in milliseconds and the scheduled date
15
17
  */
16
18
  export declare function calculateWaitTime(step: WaitInputType, now: Date): CalculateWaitTimeResult;
@@ -128,10 +128,12 @@ function calculateWaitTime(step, now) {
128
128
  };
129
129
  }
130
130
  case "relative": {
131
+ const baseTime = step.from != null ? new Date(step.from).getTime() : nowTime;
132
+ const baseDate = new Date(baseTime);
131
133
  if (!step.amount && (!step.windows || step.windows.length === 0)) {
132
134
  return {
133
- waitTime: 0,
134
- scheduledAt: now
135
+ waitTime: Math.max(0, baseTime - nowTime),
136
+ scheduledAt: baseDate
135
137
  };
136
138
  }
137
139
  let relativeDelay = 0;
@@ -170,17 +172,18 @@ function calculateWaitTime(step, now) {
170
172
  }
171
173
  }
172
174
  if (!step.windows || step.windows.length === 0) {
175
+ const scheduledAt = new Date(baseTime + relativeDelay);
173
176
  return {
174
- waitTime: relativeDelay,
175
- scheduledAt: new Date(nowTime + relativeDelay)
177
+ waitTime: Math.max(0, scheduledAt.getTime() - nowTime),
178
+ scheduledAt
176
179
  };
177
180
  }
178
- const targetDate = new Date(nowTime + relativeDelay);
181
+ const targetDate = new Date(baseTime + relativeDelay);
179
182
  for (const window of step.windows) {
180
183
  if (isTimeInWindowSlot(targetDate, window)) {
181
184
  return {
182
- waitTime: relativeDelay,
183
- scheduledAt: new Date(nowTime + relativeDelay)
185
+ waitTime: Math.max(0, targetDate.getTime() - nowTime),
186
+ scheduledAt: targetDate
184
187
  };
185
188
  }
186
189
  }
@@ -225,8 +228,8 @@ function calculateWaitTime(step, now) {
225
228
  msUntilWindowStart = daysMs + hoursAdjustment + minutesAdjustment;
226
229
  }
227
230
  const windowStartTimeMs = targetDate.getTime() + msUntilWindowStart;
228
- const sameLocalDayAsNow = getLocalDateKey(now, tz) === getLocalDateKey(targetDate, tz);
229
- const windowScheduledTime = sameLocalDayAsNow ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
231
+ const sameLocalDayAsBase = getLocalDateKey(baseDate, tz) === getLocalDateKey(targetDate, tz);
232
+ const windowScheduledTime = sameLocalDayAsBase ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
230
233
  const waitFromNow = windowScheduledTime.getTime() - nowTime;
231
234
  if (waitFromNow < earliestWaitFromNow) {
232
235
  earliestWaitFromNow = waitFromNow;