skedyul 1.5.13 → 1.7.0

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/index.js CHANGED
@@ -82,6 +82,9 @@ __export(index_exports, {
82
82
  DatePickerComponentDefinitionSchema: () => DatePickerComponentDefinitionSchema,
83
83
  DayOfWeekSchema: () => DayOfWeekSchema,
84
84
  EmptyFormComponentDefinitionSchema: () => EmptyFormComponentDefinitionSchema,
85
+ EntityDefinitionSchema: () => EntityDefinitionSchema,
86
+ EntityFieldDefinitionSchema: () => EntityFieldDefinitionSchema,
87
+ EntityRelationshipDefinitionSchema: () => EntityRelationshipDefinitionSchema,
85
88
  EnvSchemaSchema: () => EnvSchemaSchema,
86
89
  EnvVariableDefinitionSchema: () => EnvVariableDefinitionSchema,
87
90
  EnvVisibilitySchema: () => EnvVisibilitySchema,
@@ -199,6 +202,10 @@ __export(index_exports, {
199
202
  SelectComponentDefinitionSchema: () => SelectComponentDefinitionSchema,
200
203
  SemanticMemoryConfigSchema: () => SemanticMemoryConfigSchema2,
201
204
  SenderContextSchema: () => SenderContextSchema,
205
+ SequencerBackendError: () => SequencerBackendError,
206
+ SequencerContextError: () => SequencerContextError,
207
+ SequencerLockError: () => SequencerLockError,
208
+ SequencerNotFoundError: () => SequencerNotFoundError,
202
209
  SkedyulConfigSchema: () => SkedyulConfigSchema,
203
210
  SkillExampleSchema: () => SkillExampleSchema,
204
211
  SkillMetadataSchema: () => SkillMetadataSchema,
@@ -254,6 +261,7 @@ __export(index_exports, {
254
261
  buildAgentContext: () => buildAgentContext,
255
262
  calculateWaitTime: () => calculateWaitTime,
256
263
  call: () => call,
264
+ clearRegisteredSequencerConfig: () => clearRegisteredSequencerConfig,
257
265
  communicationChannel: () => communicationChannel,
258
266
  compileAgent: () => compileAgent,
259
267
  compileWorkflow: () => compileWorkflow,
@@ -273,6 +281,7 @@ __export(index_exports, {
273
281
  createPermissionError: () => createPermissionError,
274
282
  createQueueHandle: () => createQueueHandle,
275
283
  createRateLimitError: () => createRateLimitError,
284
+ createSequencerHandle: () => createSequencerHandle,
276
285
  createServerHookContext: () => createServerHookContext,
277
286
  createSuccessResponse: () => createSuccessResponse,
278
287
  createTimeoutError: () => createTimeoutError,
@@ -286,6 +295,7 @@ __export(index_exports, {
286
295
  defineAgent: () => defineAgent,
287
296
  defineChannel: () => defineChannel,
288
297
  defineConfig: () => defineConfig,
298
+ defineEntity: () => defineEntity,
289
299
  defineEnv: () => defineEnv,
290
300
  defineModel: () => defineModel,
291
301
  defineNavigation: () => defineNavigation,
@@ -311,6 +321,8 @@ __export(index_exports, {
311
321
  getRateLimitExecutionContext: () => getRateLimitExecutionContext,
312
322
  getRequiredInstallEnvKeys: () => getRequiredInstallEnvKeys,
313
323
  getRetryDelay: () => getRetryDelay,
324
+ getSequencerConfig: () => getSequencerConfig,
325
+ getSequencerDefinitions: () => getSequencerDefinitions,
314
326
  instance: () => instance,
315
327
  isChannelDependency: () => isChannelDependency,
316
328
  isCronContext: () => isCronContext,
@@ -326,20 +338,29 @@ __export(index_exports, {
326
338
  isTimeInWindowSlot: () => isTimeInWindowSlot2,
327
339
  isWorkflowDependency: () => isWorkflowDependency,
328
340
  matchesTrigger: () => matchesTrigger,
341
+ memorySequencerBackend: () => memorySequencerBackend,
329
342
  parseCRMSchema: () => parseCRMSchema,
330
343
  parseEstimationFromBilling: () => parseEstimationFromBilling,
344
+ platformSequencerBackend: () => platformSequencerBackend,
331
345
  queuedFetch: () => queuedFetch,
332
346
  queuedFetchResponse: () => queuedFetchResponse,
333
347
  registerQueueConfig: () => registerQueueConfig,
348
+ registerSequencerConfig: () => registerSequencerConfig,
334
349
  report: () => report,
335
350
  requeue: () => requeue,
351
+ resetSequencerBackendForTests: () => resetSequencerBackendForTests,
336
352
  resolveInputMappings: () => resolveInputMappings,
337
353
  resolveQueue: () => resolveQueue,
354
+ resolveSequencer: () => resolveSequencer,
338
355
  resource: () => resource,
339
356
  runWithConfig: () => runWithConfig,
340
357
  runWithRateLimitExecutionContext: () => runWithRateLimitExecutionContext,
341
358
  safeParseCRMSchema: () => safeParseCRMSchema,
342
359
  safeParseConfig: () => safeParseConfig,
360
+ sequencer: () => sequencer,
361
+ sequencerAcquire: () => acquire,
362
+ sequencerAllow: () => allow,
363
+ sequencerRelease: () => release,
343
364
  server: () => server,
344
365
  toGsm7: () => toGsm7,
345
366
  token: () => token,
@@ -760,6 +781,8 @@ var CRMPageSchemaZ = import_v43.z.object({
760
781
  icon: import_v43.z.string().optional(),
761
782
  modelHandle: import_v43.z.string(),
762
783
  parentPath: import_v43.z.string().optional(),
784
+ isDefault: import_v43.z.boolean().optional(),
785
+ visibility: import_v43.z.enum(["team", "private"]).optional(),
763
786
  baseQuery: import_v43.z.unknown().optional(),
764
787
  blocks: import_v43.z.array(CRMBlockSchemaZ).optional()
765
788
  });
@@ -1635,7 +1658,45 @@ var ModelDefinitionSchema = import_v48.z.object({
1635
1658
  addDefaultPages: import_v48.z.boolean().optional(),
1636
1659
  addNavigation: import_v48.z.boolean().optional(),
1637
1660
  /** Root path for developer resource UI (e.g., '/access_requests'). Links internal model to a provision.pages entry. */
1638
- page: import_v48.z.string().optional()
1661
+ page: import_v48.z.string().optional(),
1662
+ env: EnvSchemaSchema.optional()
1663
+ });
1664
+ var EntityFieldDefinitionSchema = import_v48.z.object({
1665
+ handle: import_v48.z.string(),
1666
+ label: import_v48.z.string(),
1667
+ description: import_v48.z.string().optional(),
1668
+ type: import_v48.z.enum([
1669
+ "string",
1670
+ "long_string",
1671
+ "number",
1672
+ "boolean",
1673
+ "date",
1674
+ "datetime",
1675
+ "object"
1676
+ ]).optional(),
1677
+ matchCandidate: import_v48.z.boolean().optional(),
1678
+ required: import_v48.z.boolean().optional(),
1679
+ options: import_v48.z.array(
1680
+ import_v48.z.union([
1681
+ import_v48.z.string(),
1682
+ import_v48.z.object({ value: import_v48.z.string(), label: import_v48.z.string() })
1683
+ ])
1684
+ ).optional()
1685
+ });
1686
+ var EntityRelationshipDefinitionSchema = import_v48.z.object({
1687
+ handle: import_v48.z.string(),
1688
+ label: import_v48.z.string(),
1689
+ targetEntity: import_v48.z.string().optional(),
1690
+ description: import_v48.z.string().optional()
1691
+ });
1692
+ var EntityDefinitionSchema = import_v48.z.object({
1693
+ handle: import_v48.z.string(),
1694
+ label: import_v48.z.string(),
1695
+ labelPlural: import_v48.z.string().optional(),
1696
+ description: import_v48.z.string().optional(),
1697
+ fields: import_v48.z.array(EntityFieldDefinitionSchema),
1698
+ contextFields: import_v48.z.array(EntityFieldDefinitionSchema).optional(),
1699
+ relationships: import_v48.z.array(EntityRelationshipDefinitionSchema).optional()
1639
1700
  });
1640
1701
  var RelationshipCardinalitySchema = import_v48.z.enum([
1641
1702
  "ONE_TO_ONE",
@@ -2205,6 +2266,8 @@ var ProvisionConfigSchema = import_v48.z.object({
2205
2266
  env: EnvSchemaSchema.optional(),
2206
2267
  /** INTERNAL model definitions (app-owned, not visible to users) */
2207
2268
  models: import_v48.z.array(ModelDefinitionSchema).optional(),
2269
+ /** App entity contracts for install-time CRM maps (not shared models) */
2270
+ entities: import_v48.z.array(EntityDefinitionSchema).optional(),
2208
2271
  /** Relationship definitions between INTERNAL models */
2209
2272
  relationships: import_v48.z.array(RelationshipDefinitionSchema).optional(),
2210
2273
  channels: import_v48.z.array(ChannelDefinitionSchema).optional(),
@@ -2447,6 +2510,56 @@ function getQueueConfigWithRetry(queueName) {
2447
2510
  return serializable;
2448
2511
  }
2449
2512
 
2513
+ // src/sequencer/config-loader.ts
2514
+ var fs2 = __toESM(require("fs"));
2515
+ var path2 = __toESM(require("path"));
2516
+ var cachedRuntimeSequencers = null;
2517
+ function getRuntimeConfigPath2() {
2518
+ if (process.env.LAMBDA_TASK_ROOT) {
2519
+ return path2.join(process.env.LAMBDA_TASK_ROOT, ".skedyul", "config.json");
2520
+ }
2521
+ return path2.join(process.cwd(), ".skedyul", "config.json");
2522
+ }
2523
+ function loadRuntimeConfigFile2() {
2524
+ const configPath = getRuntimeConfigPath2();
2525
+ if (!fs2.existsSync(configPath)) {
2526
+ return null;
2527
+ }
2528
+ try {
2529
+ const raw = fs2.readFileSync(configPath, "utf-8");
2530
+ return JSON.parse(raw);
2531
+ } catch {
2532
+ return null;
2533
+ }
2534
+ }
2535
+ var registeredServerConfig2 = null;
2536
+ function registerSequencerConfig(config) {
2537
+ registeredServerConfig2 = config;
2538
+ cachedRuntimeSequencers = config.sequencers ?? null;
2539
+ }
2540
+ function clearRegisteredSequencerConfig() {
2541
+ registeredServerConfig2 = null;
2542
+ cachedRuntimeSequencers = null;
2543
+ }
2544
+ function getSequencerDefinitions() {
2545
+ if (cachedRuntimeSequencers) {
2546
+ return cachedRuntimeSequencers;
2547
+ }
2548
+ if (registeredServerConfig2?.sequencers) {
2549
+ cachedRuntimeSequencers = registeredServerConfig2.sequencers;
2550
+ return cachedRuntimeSequencers;
2551
+ }
2552
+ const fileConfig = loadRuntimeConfigFile2();
2553
+ if (fileConfig?.sequencers) {
2554
+ cachedRuntimeSequencers = fileConfig.sequencers;
2555
+ return cachedRuntimeSequencers;
2556
+ }
2557
+ return {};
2558
+ }
2559
+ function getSequencerConfig(sequencerName) {
2560
+ return getSequencerDefinitions()[sequencerName];
2561
+ }
2562
+
2450
2563
  // src/server/utils/schema.ts
2451
2564
  var z9 = __toESM(require("zod"));
2452
2565
  function normalizeBilling(billing) {
@@ -2853,25 +2966,28 @@ function createInstanceClient(config) {
2853
2966
  pagination: pagination ?? { page: 1, total: 0, hasMore: false, limit: args?.limit ?? 50 }
2854
2967
  };
2855
2968
  },
2856
- async get(modelHandle, id) {
2969
+ async get(modelHandle, id, options) {
2857
2970
  const { data } = await callCoreWithConfig("instance.get", {
2858
2971
  modelHandle,
2859
- id
2972
+ id,
2973
+ ...options?.includeEnv ? { includeEnv: true } : {}
2860
2974
  });
2861
2975
  return data;
2862
2976
  },
2863
- async create(modelHandle, data) {
2977
+ async create(modelHandle, data, options) {
2864
2978
  const { data: inst } = await callCoreWithConfig("instance.create", {
2865
2979
  modelHandle,
2866
- data
2980
+ data,
2981
+ ...options?.env ? { env: options.env } : {}
2867
2982
  });
2868
2983
  return inst;
2869
2984
  },
2870
- async update(modelHandle, id, data) {
2985
+ async update(modelHandle, id, data, options) {
2871
2986
  const { data: inst } = await callCoreWithConfig("instance.update", {
2872
2987
  modelHandle,
2873
2988
  id,
2874
- data
2989
+ data,
2990
+ ...options?.env ? { env: options.env } : {}
2875
2991
  });
2876
2992
  return inst;
2877
2993
  },
@@ -2970,10 +3086,11 @@ var instance = {
2970
3086
  * const record = await instance.get('phone_number', 'ins_abc123')
2971
3087
  * ```
2972
3088
  */
2973
- async get(modelHandle, id) {
3089
+ async get(modelHandle, id, options) {
2974
3090
  const { data } = await callCore("instance.get", {
2975
3091
  modelHandle,
2976
- id
3092
+ id,
3093
+ ...options?.includeEnv ? { includeEnv: true } : {}
2977
3094
  });
2978
3095
  return data;
2979
3096
  },
@@ -2990,10 +3107,11 @@ var instance = {
2990
3107
  * })
2991
3108
  * ```
2992
3109
  */
2993
- async create(modelHandle, data) {
3110
+ async create(modelHandle, data, options) {
2994
3111
  const { data: instance2 } = await callCore("instance.create", {
2995
3112
  modelHandle,
2996
- data
3113
+ data,
3114
+ ...options?.env ? { env: options.env } : {}
2997
3115
  });
2998
3116
  return instance2;
2999
3117
  },
@@ -3010,11 +3128,12 @@ var instance = {
3010
3128
  * })
3011
3129
  * ```
3012
3130
  */
3013
- async update(modelHandle, id, data) {
3131
+ async update(modelHandle, id, data, options) {
3014
3132
  const { data: instance2 } = await callCore("instance.update", {
3015
3133
  modelHandle,
3016
3134
  id,
3017
- data
3135
+ data,
3136
+ ...options?.env ? { env: options.env } : {}
3018
3137
  });
3019
3138
  return instance2;
3020
3139
  },
@@ -4381,7 +4500,7 @@ function printStartupLog(config, tools, port) {
4381
4500
 
4382
4501
  // src/server/route-handlers/adapters.ts
4383
4502
  function fromLambdaEvent(event2) {
4384
- const path5 = event2.path || event2.rawPath || "/";
4503
+ const path6 = event2.path || event2.rawPath || "/";
4385
4504
  const method = event2.httpMethod || event2.requestContext?.http?.method || "POST";
4386
4505
  const forwardedProto = event2.headers?.["x-forwarded-proto"] ?? event2.headers?.["X-Forwarded-Proto"];
4387
4506
  const protocol = forwardedProto ?? "https";
@@ -4389,9 +4508,9 @@ function fromLambdaEvent(event2) {
4389
4508
  const queryString = event2.queryStringParameters ? "?" + new URLSearchParams(
4390
4509
  event2.queryStringParameters
4391
4510
  ).toString() : "";
4392
- const url = `${protocol}://${host}${path5}${queryString}`;
4511
+ const url = `${protocol}://${host}${path6}${queryString}`;
4393
4512
  return {
4394
- path: path5,
4513
+ path: path6,
4395
4514
  method,
4396
4515
  headers: event2.headers,
4397
4516
  query: event2.queryStringParameters ?? {},
@@ -4473,8 +4592,8 @@ function parseBodyByContentType(req) {
4473
4592
  }
4474
4593
 
4475
4594
  // src/server/route-handlers/handlers.ts
4476
- var fs2 = __toESM(require("fs"));
4477
- var path2 = __toESM(require("path"));
4595
+ var fs3 = __toESM(require("fs"));
4596
+ var path3 = __toESM(require("path"));
4478
4597
 
4479
4598
  // src/server/core-api-handler.ts
4480
4599
  async function handleCoreMethod(method, params) {
@@ -4942,7 +5061,7 @@ async function handleOAuthCallback(parsedBody, hooks) {
4942
5061
  }
4943
5062
 
4944
5063
  // src/server/handlers/webhook-handler.ts
4945
- function parseWebhookRequest(parsedBody, method, url, path5, headers, query, rawBody, appIdHeader, appVersionIdHeader) {
5064
+ function parseWebhookRequest(parsedBody, method, url, path6, headers, query, rawBody, appIdHeader, appVersionIdHeader) {
4946
5065
  const isEnvelope = typeof parsedBody === "object" && parsedBody !== null && "env" in parsedBody && "request" in parsedBody && "context" in parsedBody;
4947
5066
  if (isEnvelope) {
4948
5067
  const envelope = parsedBody;
@@ -4996,7 +5115,7 @@ function parseWebhookRequest(parsedBody, method, url, path5, headers, query, raw
4996
5115
  const webhookRequest = {
4997
5116
  method,
4998
5117
  url,
4999
- path: path5,
5118
+ path: path6,
5000
5119
  headers,
5001
5120
  query,
5002
5121
  body: parsedBody,
@@ -5025,9 +5144,17 @@ async function executeWebhookHandler(handle, webhookRegistry, data) {
5025
5144
  };
5026
5145
  let webhookResponse;
5027
5146
  try {
5147
+ const rateLimitContext = {
5148
+ app: data.webhookContext.app,
5149
+ appInstallationId: isRuntimeWebhookContext(data.webhookContext) ? data.webhookContext.appInstallationId : void 0,
5150
+ invocation: data.invocation,
5151
+ isProvisionContext: !isRuntimeWebhookContext(data.webhookContext)
5152
+ };
5028
5153
  webhookResponse = await runWithLogContext({ invocation: data.invocation }, async () => {
5029
5154
  return await runWithConfig(requestConfig, async () => {
5030
- return await webhookDef.handler(data.webhookRequest, data.webhookContext);
5155
+ return await runWithRateLimitExecutionContext(rateLimitContext, async () => {
5156
+ return await webhookDef.handler(data.webhookRequest, data.webhookContext);
5157
+ });
5031
5158
  });
5032
5159
  });
5033
5160
  } catch (err) {
@@ -5054,7 +5181,7 @@ function isMethodAllowed(webhookRegistry, handle, method) {
5054
5181
 
5055
5182
  // src/server/route-handlers/handlers.ts
5056
5183
  function getConfigFilePath() {
5057
- return process.env.LAMBDA_TASK_ROOT ? path2.join(process.env.LAMBDA_TASK_ROOT, ".skedyul", "config.json") : ".skedyul/config.json";
5184
+ return process.env.LAMBDA_TASK_ROOT ? path3.join(process.env.LAMBDA_TASK_ROOT, ".skedyul", "config.json") : ".skedyul/config.json";
5058
5185
  }
5059
5186
  function findToolInRegistry(registry, toolName) {
5060
5187
  for (const [key, t] of Object.entries(registry)) {
@@ -5093,8 +5220,8 @@ function handleHealthRoute(ctx) {
5093
5220
  function handleConfigRoute(ctx) {
5094
5221
  const configFilePath = getConfigFilePath();
5095
5222
  try {
5096
- if (fs2.existsSync(configFilePath)) {
5097
- const fileConfig = JSON.parse(fs2.readFileSync(configFilePath, "utf-8"));
5223
+ if (fs3.existsSync(configFilePath)) {
5224
+ const fileConfig = JSON.parse(fs3.readFileSync(configFilePath, "utf-8"));
5098
5225
  return { status: 200, body: fileConfig };
5099
5226
  }
5100
5227
  } catch (err) {
@@ -5782,6 +5909,7 @@ installContextLogger();
5782
5909
  function createSkedyulServer(config) {
5783
5910
  mergeRuntimeEnv();
5784
5911
  registerQueueConfig(config);
5912
+ registerSequencerConfig(config);
5785
5913
  const registry = config.tools;
5786
5914
  const webhookRegistry = config.webhooks;
5787
5915
  if (config.coreApi?.service) {
@@ -6030,6 +6158,9 @@ function defineConfig(config) {
6030
6158
  function defineModel(model) {
6031
6159
  return model;
6032
6160
  }
6161
+ function defineEntity(entity) {
6162
+ return entity;
6163
+ }
6033
6164
  function defineChannel(channel) {
6034
6165
  return channel;
6035
6166
  }
@@ -6050,13 +6181,13 @@ function defineNavigation(navigation) {
6050
6181
  }
6051
6182
 
6052
6183
  // src/config/schema-loader.ts
6053
- var fs3 = __toESM(require("fs"));
6054
- var path3 = __toESM(require("path"));
6184
+ var fs4 = __toESM(require("fs"));
6185
+ var path4 = __toESM(require("path"));
6055
6186
  var os = __toESM(require("os"));
6056
6187
 
6057
6188
  // src/config/resolver.ts
6058
- var fs4 = __toESM(require("fs"));
6059
- var path4 = __toESM(require("path"));
6189
+ var fs5 = __toESM(require("fs"));
6190
+ var path5 = __toESM(require("path"));
6060
6191
 
6061
6192
  // src/config/utils.ts
6062
6193
  function getAllEnvKeys(config) {
@@ -6159,7 +6290,7 @@ function getApiToken() {
6159
6290
  const config = getConfig();
6160
6291
  return config.apiToken || process.env.SKEDYUL_API_TOKEN || "";
6161
6292
  }
6162
- async function callRateLimitApi(path5, body) {
6293
+ async function callRateLimitApi(path6, body) {
6163
6294
  const baseUrl = getApiBaseUrl();
6164
6295
  const token2 = getApiToken();
6165
6296
  if (!baseUrl || !token2) {
@@ -6167,7 +6298,7 @@ async function callRateLimitApi(path5, body) {
6167
6298
  "SKEDYUL_API_URL and SKEDYUL_API_TOKEN are required for platform queue coordination"
6168
6299
  );
6169
6300
  }
6170
- const response = await fetch(`${baseUrl}/api/internal/ratelimit/${path5}`, {
6301
+ const response = await fetch(`${baseUrl}/api/internal/ratelimit/${path6}`, {
6171
6302
  method: "POST",
6172
6303
  headers: {
6173
6304
  Authorization: `Bearer ${token2}`,
@@ -6177,11 +6308,11 @@ async function callRateLimitApi(path5, body) {
6177
6308
  });
6178
6309
  const payload = await response.json().catch(() => null);
6179
6310
  if (!response.ok || payload?.success === false) {
6180
- const message = payload?.errors?.[0]?.message ?? `Queue coordination API ${path5} failed with status ${response.status}`;
6311
+ const message = payload?.errors?.[0]?.message ?? `Queue coordination API ${path6} failed with status ${response.status}`;
6181
6312
  throw new RateLimitBackendError(message, response.status);
6182
6313
  }
6183
6314
  if (!payload?.data) {
6184
- throw new RateLimitBackendError(`Queue coordination API ${path5} returned empty data`);
6315
+ throw new RateLimitBackendError(`Queue coordination API ${path6} returned empty data`);
6185
6316
  }
6186
6317
  return payload.data;
6187
6318
  }
@@ -6636,6 +6767,406 @@ async function queuedFetchResponse(queueInput, url, init) {
6636
6767
  return queuedFetch(queueInput, () => fetch(url, init));
6637
6768
  }
6638
6769
 
6770
+ // src/sequencer/errors.ts
6771
+ var SequencerContextError = class extends Error {
6772
+ constructor(message) {
6773
+ super(message);
6774
+ this.code = "SEQUENCER_CONTEXT_ERROR";
6775
+ this.name = "SequencerContextError";
6776
+ }
6777
+ };
6778
+ var SequencerNotFoundError = class extends Error {
6779
+ constructor(name) {
6780
+ super(`Sequencer "${name}" is not defined in skedyul.config`);
6781
+ this.code = "SEQUENCER_NOT_FOUND";
6782
+ this.name = "SequencerNotFoundError";
6783
+ }
6784
+ };
6785
+ var SequencerBackendError = class extends Error {
6786
+ constructor(message, statusCode) {
6787
+ super(message);
6788
+ this.code = "SEQUENCER_BACKEND_ERROR";
6789
+ this.name = "SequencerBackendError";
6790
+ this.statusCode = statusCode;
6791
+ }
6792
+ };
6793
+ var SequencerLockError = class extends Error {
6794
+ constructor(message) {
6795
+ super(message);
6796
+ this.code = "SEQUENCER_LOCK_ERROR";
6797
+ this.name = "SequencerLockError";
6798
+ }
6799
+ };
6800
+
6801
+ // src/sequencer/resolve-sequencer-key.ts
6802
+ function resolveEndpointHandle2(config, invocation) {
6803
+ if (config.endpoint) {
6804
+ return config.endpoint;
6805
+ }
6806
+ if (invocation?.toolHandle) {
6807
+ return invocation.toolHandle;
6808
+ }
6809
+ if (invocation?.serverHookHandle) {
6810
+ return invocation.serverHookHandle;
6811
+ }
6812
+ throw new SequencerContextError(
6813
+ `Cannot resolve endpoint handle for sequencer scope "${config.scope}". Set endpoint in sequencer config or ensure invocation.toolHandle/serverHookHandle is available.`
6814
+ );
6815
+ }
6816
+ function appendSubKey2(base, subKey) {
6817
+ return subKey ? `${base}:${subKey}` : base;
6818
+ }
6819
+ function resolveSequencerKey(sequencerName, config, ctx, subKey) {
6820
+ const { app, appInstallationId, invocation, isProvisionContext: isProvisionContext2 } = ctx;
6821
+ switch (config.scope) {
6822
+ case "provision": {
6823
+ const base = `seq:pv:${app.versionId}:${sequencerName}`;
6824
+ return appendSubKey2(base, subKey);
6825
+ }
6826
+ case "install": {
6827
+ if (!appInstallationId) {
6828
+ throw new SequencerContextError(
6829
+ `Sequencer "${sequencerName}" with scope "install" requires appInstallationId in context`
6830
+ );
6831
+ }
6832
+ const base = `seq:in:${appInstallationId}:${sequencerName}`;
6833
+ return appendSubKey2(base, subKey);
6834
+ }
6835
+ case "provision_endpoint": {
6836
+ if (!isProvisionContext2 && appInstallationId) {
6837
+ throw new SequencerContextError(
6838
+ `Sequencer "${sequencerName}" with scope "provision_endpoint" requires provision context (no install)`
6839
+ );
6840
+ }
6841
+ const endpointHandle = resolveEndpointHandle2(config, invocation);
6842
+ const base = `seq:pep:${app.versionId}:${endpointHandle}:${sequencerName}`;
6843
+ return appendSubKey2(base, subKey);
6844
+ }
6845
+ case "install_endpoint": {
6846
+ if (!appInstallationId) {
6847
+ throw new SequencerContextError(
6848
+ `Sequencer "${sequencerName}" with scope "install_endpoint" requires appInstallationId in context`
6849
+ );
6850
+ }
6851
+ const endpointHandle = resolveEndpointHandle2(config, invocation);
6852
+ const base = `seq:iep:${appInstallationId}:${endpointHandle}:${sequencerName}`;
6853
+ return appendSubKey2(base, subKey);
6854
+ }
6855
+ case "global": {
6856
+ const base = `seq:gl:${app.versionId}:${sequencerName}`;
6857
+ return appendSubKey2(base, subKey);
6858
+ }
6859
+ default: {
6860
+ const _exhaustive = config.scope;
6861
+ throw new SequencerContextError(`Unknown sequencer scope: ${String(_exhaustive)}`);
6862
+ }
6863
+ }
6864
+ }
6865
+
6866
+ // src/sequencer/backends/platform.ts
6867
+ function getApiBaseUrl2() {
6868
+ const config = getConfig();
6869
+ if (config.baseUrl) {
6870
+ return config.baseUrl.replace(/\/+$/, "");
6871
+ }
6872
+ return (process.env.SKEDYUL_API_URL ?? process.env.SKEDYUL_NODE_URL ?? "").replace(/\/+$/, "");
6873
+ }
6874
+ function getApiToken2() {
6875
+ const config = getConfig();
6876
+ return config.apiToken || process.env.SKEDYUL_API_TOKEN || "";
6877
+ }
6878
+ async function callSequencerApi(path6, body) {
6879
+ const baseUrl = getApiBaseUrl2();
6880
+ const token2 = getApiToken2();
6881
+ if (!baseUrl || !token2) {
6882
+ throw new SequencerBackendError(
6883
+ "SKEDYUL_API_URL and SKEDYUL_API_TOKEN are required for platform sequencer coordination"
6884
+ );
6885
+ }
6886
+ const response = await fetch(`${baseUrl}/api/internal/sequencer/${path6}`, {
6887
+ method: "POST",
6888
+ headers: {
6889
+ Authorization: `Bearer ${token2}`,
6890
+ "Content-Type": "application/json"
6891
+ },
6892
+ body: JSON.stringify(body)
6893
+ });
6894
+ const payload = await response.json().catch(() => null);
6895
+ if (!response.ok || payload?.success === false) {
6896
+ const message = payload?.errors?.[0]?.message ?? `Sequencer coordination API ${path6} failed with status ${response.status}`;
6897
+ throw new SequencerBackendError(message, response.status);
6898
+ }
6899
+ if (!payload?.data) {
6900
+ throw new SequencerBackendError(`Sequencer coordination API ${path6} returned empty data`);
6901
+ }
6902
+ return payload.data;
6903
+ }
6904
+ var PlatformSequencerBackend = class {
6905
+ async allow(sequencerKey, input) {
6906
+ return callSequencerApi("allow", {
6907
+ sequencerKey,
6908
+ timestamp: input.timestamp,
6909
+ leaseId: input.leaseId,
6910
+ watermarkTtlMs: input.watermarkTtlMs
6911
+ });
6912
+ }
6913
+ async acquire(sequencerKey, input) {
6914
+ return callSequencerApi("acquire", {
6915
+ sequencerKey,
6916
+ leaseId: input.leaseId,
6917
+ timestamp: input.timestamp,
6918
+ lockTtlMs: input.lockTtlMs,
6919
+ watermarkTtlMs: input.watermarkTtlMs
6920
+ });
6921
+ }
6922
+ async release(sequencerKey, leaseId) {
6923
+ await callSequencerApi("release", {
6924
+ sequencerKey,
6925
+ leaseId
6926
+ });
6927
+ }
6928
+ };
6929
+ var platformSequencerBackend = new PlatformSequencerBackend();
6930
+
6931
+ // src/sequencer/backends/memory.ts
6932
+ function generateLeaseId2() {
6933
+ return `mem_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
6934
+ }
6935
+ var MemorySequencerBackend = class {
6936
+ constructor() {
6937
+ this.state = /* @__PURE__ */ new Map();
6938
+ }
6939
+ getState(sequencerKey) {
6940
+ let state = this.state.get(sequencerKey);
6941
+ if (!state) {
6942
+ state = { watermark: 0, lockLeaseId: null, lockExpiresAt: 0 };
6943
+ this.state.set(sequencerKey, state);
6944
+ }
6945
+ if (state.lockLeaseId && state.lockExpiresAt <= Date.now()) {
6946
+ state.lockLeaseId = null;
6947
+ state.lockExpiresAt = 0;
6948
+ }
6949
+ return state;
6950
+ }
6951
+ async allow(sequencerKey, input) {
6952
+ void input.watermarkTtlMs;
6953
+ const state = this.getState(sequencerKey);
6954
+ if (input.timestamp < state.watermark) {
6955
+ return { allowed: false, reason: "stale", watermark: state.watermark };
6956
+ }
6957
+ if (state.lockLeaseId && input.leaseId && state.lockLeaseId !== input.leaseId) {
6958
+ return { allowed: false, reason: "locked", watermark: state.watermark };
6959
+ }
6960
+ state.watermark = Math.max(state.watermark, input.timestamp);
6961
+ return { allowed: true, reason: "ok", watermark: state.watermark };
6962
+ }
6963
+ async acquire(sequencerKey, input) {
6964
+ void input.watermarkTtlMs;
6965
+ const state = this.getState(sequencerKey);
6966
+ const leaseId = input.leaseId || generateLeaseId2();
6967
+ if (state.lockLeaseId && state.lockLeaseId !== leaseId) {
6968
+ return { acquired: false, reason: "locked" };
6969
+ }
6970
+ state.lockLeaseId = leaseId;
6971
+ state.lockExpiresAt = Date.now() + (input.lockTtlMs ?? 6e4);
6972
+ if (input.timestamp !== void 0) {
6973
+ state.watermark = Math.max(state.watermark, input.timestamp);
6974
+ }
6975
+ return { acquired: true, reason: "ok" };
6976
+ }
6977
+ async release(sequencerKey, leaseId) {
6978
+ const state = this.state.get(sequencerKey);
6979
+ if (!state || state.lockLeaseId !== leaseId) {
6980
+ return;
6981
+ }
6982
+ state.lockLeaseId = null;
6983
+ state.lockExpiresAt = 0;
6984
+ }
6985
+ resetForTests() {
6986
+ this.state.clear();
6987
+ }
6988
+ };
6989
+ var memorySequencerBackend = new MemorySequencerBackend();
6990
+
6991
+ // src/sequencer/backends/index.ts
6992
+ var cachedBackend2 = null;
6993
+ function shouldForceMemoryBackend2() {
6994
+ const flag = process.env.SKEDYUL_SEQUENCER_MEMORY;
6995
+ return flag === "1" || flag === "true";
6996
+ }
6997
+ function getSequencerBackend() {
6998
+ if (cachedBackend2) {
6999
+ return cachedBackend2;
7000
+ }
7001
+ if (shouldForceMemoryBackend2()) {
7002
+ cachedBackend2 = memorySequencerBackend;
7003
+ return cachedBackend2;
7004
+ }
7005
+ cachedBackend2 = createResilientBackend2();
7006
+ return cachedBackend2;
7007
+ }
7008
+ function createResilientBackend2() {
7009
+ return {
7010
+ async allow(sequencerKey, input) {
7011
+ try {
7012
+ return await platformSequencerBackend.allow(sequencerKey, input);
7013
+ } catch (error) {
7014
+ if (shouldFallbackToMemory2(error)) {
7015
+ return memorySequencerBackend.allow(sequencerKey, input);
7016
+ }
7017
+ throw error;
7018
+ }
7019
+ },
7020
+ async acquire(sequencerKey, input) {
7021
+ try {
7022
+ return await platformSequencerBackend.acquire(sequencerKey, input);
7023
+ } catch (error) {
7024
+ if (shouldFallbackToMemory2(error)) {
7025
+ return memorySequencerBackend.acquire(sequencerKey, input);
7026
+ }
7027
+ throw error;
7028
+ }
7029
+ },
7030
+ async release(sequencerKey, leaseId) {
7031
+ if (leaseId.startsWith("mem_")) {
7032
+ return memorySequencerBackend.release(sequencerKey, leaseId);
7033
+ }
7034
+ try {
7035
+ await platformSequencerBackend.release(sequencerKey, leaseId);
7036
+ } catch (error) {
7037
+ if (shouldFallbackToMemory2(error)) {
7038
+ return memorySequencerBackend.release(sequencerKey, leaseId);
7039
+ }
7040
+ throw error;
7041
+ }
7042
+ }
7043
+ };
7044
+ }
7045
+ function shouldFallbackToMemory2(error) {
7046
+ if (shouldForceMemoryBackend2()) {
7047
+ return true;
7048
+ }
7049
+ if (error instanceof SequencerBackendError) {
7050
+ if (error.statusCode === 404 || error.statusCode === 503) {
7051
+ return true;
7052
+ }
7053
+ }
7054
+ if (error instanceof TypeError) {
7055
+ return true;
7056
+ }
7057
+ const nodeEnv = process.env.NODE_ENV;
7058
+ return nodeEnv === "development" || nodeEnv === "test";
7059
+ }
7060
+ function resetSequencerBackendForTests() {
7061
+ cachedBackend2 = null;
7062
+ }
7063
+
7064
+ // src/sequencer/index.ts
7065
+ function normalizeSequencerInput(input) {
7066
+ if (typeof input === "string") {
7067
+ return { name: input };
7068
+ }
7069
+ return { name: input.sequencer, subKey: input.key };
7070
+ }
7071
+ function mergeContext(ctxOverride) {
7072
+ const ctx = getRateLimitExecutionContext();
7073
+ if (!ctx?.app?.versionId) {
7074
+ throw new SequencerContextError(
7075
+ "Cannot resolve sequencer without app context. Ensure sequencer runs inside a tool/hook/webhook handler."
7076
+ );
7077
+ }
7078
+ return { ...ctx, ...ctxOverride };
7079
+ }
7080
+ function resolveSequencer(sequencerInput, ctxOverride) {
7081
+ const ctx = mergeContext(ctxOverride);
7082
+ const { name, subKey } = normalizeSequencerInput(sequencerInput);
7083
+ const config = getSequencerConfig(name);
7084
+ if (!config) {
7085
+ throw new SequencerNotFoundError(name);
7086
+ }
7087
+ const sequencerKey = resolveSequencerKey(name, config, ctx, subKey);
7088
+ return { name, sequencerKey, config };
7089
+ }
7090
+ function createSequencerHandle(sequencerInput, ctxOverride) {
7091
+ return {
7092
+ allow(input) {
7093
+ return allow(sequencerInput, input, ctxOverride);
7094
+ },
7095
+ acquire(input) {
7096
+ return acquire(sequencerInput, input, ctxOverride);
7097
+ },
7098
+ release(input) {
7099
+ return release(sequencerInput, input, ctxOverride);
7100
+ }
7101
+ };
7102
+ }
7103
+ function disabledAllowResult() {
7104
+ return { allowed: true, reason: "disabled" };
7105
+ }
7106
+ async function allow(sequencerInput, input, ctxOverride) {
7107
+ const { name, subKey } = normalizeSequencerInput(sequencerInput);
7108
+ const config = getSequencerConfig(name);
7109
+ if (!config || config.enabled !== true) {
7110
+ return disabledAllowResult();
7111
+ }
7112
+ const resolvedSubKey = input.key ?? subKey;
7113
+ const resolved = resolveSequencer(
7114
+ { sequencer: name, key: resolvedSubKey },
7115
+ ctxOverride
7116
+ );
7117
+ const backend = getSequencerBackend();
7118
+ return backend.allow(resolved.sequencerKey, {
7119
+ timestamp: input.timestamp,
7120
+ leaseId: input.leaseId,
7121
+ watermarkTtlMs: resolved.config.watermarkTtlMs
7122
+ });
7123
+ }
7124
+ async function acquire(sequencerInput, input, ctxOverride) {
7125
+ const { name, subKey } = normalizeSequencerInput(sequencerInput);
7126
+ const config = getSequencerConfig(name);
7127
+ if (!config || config.enabled !== true) {
7128
+ return;
7129
+ }
7130
+ const resolvedSubKey = input.key ?? subKey;
7131
+ const resolved = resolveSequencer(
7132
+ { sequencer: name, key: resolvedSubKey },
7133
+ ctxOverride
7134
+ );
7135
+ const backend = getSequencerBackend();
7136
+ const result = await backend.acquire(resolved.sequencerKey, {
7137
+ leaseId: input.leaseId,
7138
+ timestamp: input.timestamp,
7139
+ lockTtlMs: input.lockTtlMs ?? resolved.config.lockTtlMs,
7140
+ watermarkTtlMs: resolved.config.watermarkTtlMs
7141
+ });
7142
+ if (!result.acquired) {
7143
+ throw new SequencerLockError(
7144
+ `Sequencer "${name}" lock held by another lease (${result.reason})`
7145
+ );
7146
+ }
7147
+ }
7148
+ async function release(sequencerInput, input, ctxOverride) {
7149
+ const { name, subKey } = normalizeSequencerInput(sequencerInput);
7150
+ const config = getSequencerConfig(name);
7151
+ if (!config || config.enabled !== true) {
7152
+ return;
7153
+ }
7154
+ const resolvedSubKey = input.key ?? subKey;
7155
+ const resolved = resolveSequencer(
7156
+ { sequencer: name, key: resolvedSubKey },
7157
+ ctxOverride
7158
+ );
7159
+ const backend = getSequencerBackend();
7160
+ await backend.release(resolved.sequencerKey, input.leaseId);
7161
+ }
7162
+ var sequencer = {
7163
+ allow,
7164
+ acquire,
7165
+ release,
7166
+ resolve: resolveSequencer,
7167
+ createHandle: createSequencerHandle
7168
+ };
7169
+
6639
7170
  // src/triggers/types.ts
6640
7171
  var import_v410 = require("zod/v4");
6641
7172
  var CRMDataSchema = import_v410.z.object({
@@ -6740,16 +7271,16 @@ function evaluateTemplate(template, context) {
6740
7271
  const templateRegex = /\{\{\s*([^}]+)\s*\}\}/g;
6741
7272
  const singleMatch = template.match(/^\{\{\s*([^}]+)\s*\}\}$/);
6742
7273
  if (singleMatch) {
6743
- const path5 = singleMatch[1].trim();
6744
- return resolvePath(context, path5);
7274
+ const path6 = singleMatch[1].trim();
7275
+ return resolvePath(context, path6);
6745
7276
  }
6746
- return template.replace(templateRegex, (_, path5) => {
6747
- const value = resolvePath(context, path5.trim());
7277
+ return template.replace(templateRegex, (_, path6) => {
7278
+ const value = resolvePath(context, path6.trim());
6748
7279
  return value === void 0 || value === null ? "" : String(value);
6749
7280
  });
6750
7281
  }
6751
- function resolvePath(obj, path5) {
6752
- const parts = path5.split(".");
7282
+ function resolvePath(obj, path6) {
7283
+ const parts = path6.split(".");
6753
7284
  let current = obj;
6754
7285
  for (const part of parts) {
6755
7286
  if (current === null || current === void 0) {
@@ -6770,14 +7301,14 @@ function evaluateCondition(condition, context) {
6770
7301
  const expression = match[1].trim();
6771
7302
  const eqMatch = expression.match(/^(.+?)\s*==\s*['"](.+)['"]$/);
6772
7303
  if (eqMatch) {
6773
- const [, path5, expectedValue] = eqMatch;
6774
- const actualValue = resolvePath(context, path5.trim());
7304
+ const [, path6, expectedValue] = eqMatch;
7305
+ const actualValue = resolvePath(context, path6.trim());
6775
7306
  return actualValue === expectedValue;
6776
7307
  }
6777
7308
  const neqMatch = expression.match(/^(.+?)\s*!=\s*['"](.+)['"]$/);
6778
7309
  if (neqMatch) {
6779
- const [, path5, expectedValue] = neqMatch;
6780
- const actualValue = resolvePath(context, path5.trim());
7310
+ const [, path6, expectedValue] = neqMatch;
7311
+ const actualValue = resolvePath(context, path6.trim());
6781
7312
  return actualValue !== expectedValue;
6782
7313
  }
6783
7314
  const value = resolvePath(context, expression);
@@ -8113,6 +8644,9 @@ var index_default = { z: import_v414.z };
8113
8644
  DatePickerComponentDefinitionSchema,
8114
8645
  DayOfWeekSchema,
8115
8646
  EmptyFormComponentDefinitionSchema,
8647
+ EntityDefinitionSchema,
8648
+ EntityFieldDefinitionSchema,
8649
+ EntityRelationshipDefinitionSchema,
8116
8650
  EnvSchemaSchema,
8117
8651
  EnvVariableDefinitionSchema,
8118
8652
  EnvVisibilitySchema,
@@ -8230,6 +8764,10 @@ var index_default = { z: import_v414.z };
8230
8764
  SelectComponentDefinitionSchema,
8231
8765
  SemanticMemoryConfigSchema,
8232
8766
  SenderContextSchema,
8767
+ SequencerBackendError,
8768
+ SequencerContextError,
8769
+ SequencerLockError,
8770
+ SequencerNotFoundError,
8233
8771
  SkedyulConfigSchema,
8234
8772
  SkillExampleSchema,
8235
8773
  SkillMetadataSchema,
@@ -8285,6 +8823,7 @@ var index_default = { z: import_v414.z };
8285
8823
  buildAgentContext,
8286
8824
  calculateWaitTime,
8287
8825
  call,
8826
+ clearRegisteredSequencerConfig,
8288
8827
  communicationChannel,
8289
8828
  compileAgent,
8290
8829
  compileWorkflow,
@@ -8304,6 +8843,7 @@ var index_default = { z: import_v414.z };
8304
8843
  createPermissionError,
8305
8844
  createQueueHandle,
8306
8845
  createRateLimitError,
8846
+ createSequencerHandle,
8307
8847
  createServerHookContext,
8308
8848
  createSuccessResponse,
8309
8849
  createTimeoutError,
@@ -8316,6 +8856,7 @@ var index_default = { z: import_v414.z };
8316
8856
  defineAgent,
8317
8857
  defineChannel,
8318
8858
  defineConfig,
8859
+ defineEntity,
8319
8860
  defineEnv,
8320
8861
  defineModel,
8321
8862
  defineNavigation,
@@ -8341,6 +8882,8 @@ var index_default = { z: import_v414.z };
8341
8882
  getRateLimitExecutionContext,
8342
8883
  getRequiredInstallEnvKeys,
8343
8884
  getRetryDelay,
8885
+ getSequencerConfig,
8886
+ getSequencerDefinitions,
8344
8887
  instance,
8345
8888
  isChannelDependency,
8346
8889
  isCronContext,
@@ -8356,20 +8899,29 @@ var index_default = { z: import_v414.z };
8356
8899
  isTimeInWindowSlot,
8357
8900
  isWorkflowDependency,
8358
8901
  matchesTrigger,
8902
+ memorySequencerBackend,
8359
8903
  parseCRMSchema,
8360
8904
  parseEstimationFromBilling,
8905
+ platformSequencerBackend,
8361
8906
  queuedFetch,
8362
8907
  queuedFetchResponse,
8363
8908
  registerQueueConfig,
8909
+ registerSequencerConfig,
8364
8910
  report,
8365
8911
  requeue,
8912
+ resetSequencerBackendForTests,
8366
8913
  resolveInputMappings,
8367
8914
  resolveQueue,
8915
+ resolveSequencer,
8368
8916
  resource,
8369
8917
  runWithConfig,
8370
8918
  runWithRateLimitExecutionContext,
8371
8919
  safeParseCRMSchema,
8372
8920
  safeParseConfig,
8921
+ sequencer,
8922
+ sequencerAcquire,
8923
+ sequencerAllow,
8924
+ sequencerRelease,
8373
8925
  server,
8374
8926
  toGsm7,
8375
8927
  token,