@superdurable/connectors-sdk 0.1.1 → 0.2.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.
@@ -1,48 +1,14 @@
1
- // src/errors.ts
2
- import { z } from "zod";
3
- var FailureKindSchema = z.enum([
4
- "VALIDATION",
5
- "AUTHENTICATION",
6
- "AUTHORIZATION",
7
- "NOT_FOUND",
8
- "CONFLICT",
9
- "RATE_LIMIT",
10
- "QUOTA_EXHAUSTED",
11
- "AVAILABILITY",
12
- "PROVIDER_REJECTION",
13
- "TRANSPORT",
14
- "RESPONSE_TOO_LARGE",
15
- "PROTOCOL",
16
- "LOCAL_DEFECT"
17
- ]);
18
- var FailureSchema = z.strictObject({ kind: FailureKindSchema, provider: z.string().min(1), operation: z.string().min(1), message: z.string().min(1) });
19
- var RetryError = class extends Error {
20
- /** Validated provider fact behind the retry request. */
21
- failure;
22
- /** Provider-requested retry delay in milliseconds; zero uses the Step policy. */
23
- retryAfterMs;
24
- constructor(failure, retryAfterMs = 0) {
25
- const validated = FailureSchema.parse(failure);
26
- super(`connector ${validated.provider} ${validated.operation} retry (${validated.kind}): ${validated.message}`);
27
- this.name = "RetryError";
28
- this.failure = validated;
29
- this.retryAfterMs = retryAfterMs;
30
- }
31
- };
32
- var ReauthorizationRequiredError = class extends Error {
33
- constructor() {
34
- super("connector reauthorization is required");
35
- this.name = "ReauthorizationRequiredError";
36
- }
37
- };
1
+ import {
2
+ FailureSchema
3
+ } from "./chunk-IHG6ADQG.js";
38
4
 
39
5
  // src/types.ts
40
- import { z as z2 } from "zod";
6
+ import { z } from "zod";
41
7
  import { createHash } from "crypto";
42
- var CallIDSchema = z2.uuid();
8
+ var CallIDSchema = z.uuid();
43
9
  var CallIDNamespace = "63281a42-70ad-5bc3-a289-728819af723f";
44
- var ConnectionRefSchema = z2.strictObject({ provider: z2.string().refine((value) => value.trim().length > 0), name: z2.string().refine((value) => value.trim().length > 0) });
45
- var OperationRefSchema = z2.strictObject({ connectorId: z2.string().regex(/^[a-z][a-z0-9-]{1,62}$/), operationId: z2.string().regex(/^[a-z][A-Za-z0-9]+$/) });
10
+ var ConnectionRefSchema = z.strictObject({ provider: z.string().refine((value) => value.trim().length > 0), name: z.string().refine((value) => value.trim().length > 0) });
11
+ var OperationRefSchema = z.strictObject({ connectorId: z.string().regex(/^[a-z][a-z0-9-]{1,62}$/), operationId: z.string().regex(/^[a-z][A-Za-z0-9]+$/) });
46
12
  function deriveCallID(flowId, stepExecutionId, operation) {
47
13
  OperationRefSchema.parse(operation);
48
14
  const namespace = CallIDNamespace;
@@ -68,28 +34,28 @@ function uuidSHA1(namespace, name) {
68
34
  }
69
35
  var DefectBranchID = "defect";
70
36
  var UncertainBranchID = "uncertain";
71
- var BranchDefinitionSchema = z2.strictObject({ id: z2.string().min(1), description: z2.string(), optional: z2.boolean().optional() });
72
- var StepDefaultsWireSchema = z2.strictObject({
73
- executeMethodTimeout: z2.number().int().nonnegative(),
74
- heartbeatTimeout: z2.number().int().nonnegative().optional(),
75
- executeRetry: z2.strictObject({ InitialInterval: z2.number().int().nonnegative(), BackoffCoefficient: z2.number().positive(), MaximumInterval: z2.number().int().nonnegative(), MaximumAttempts: z2.number().int().nonnegative(), TotalDuration: z2.number().int().nonnegative() }).optional(),
76
- executeDurability: z2.number().int()
37
+ var BranchDefinitionSchema = z.strictObject({ id: z.string().min(1), description: z.string(), optional: z.boolean().optional() });
38
+ var StepDefaultsWireSchema = z.strictObject({
39
+ executeMethodTimeout: z.number().int().nonnegative(),
40
+ heartbeatTimeout: z.number().int().nonnegative().optional(),
41
+ executeRetry: z.strictObject({ InitialInterval: z.number().int().nonnegative(), BackoffCoefficient: z.number().positive(), MaximumInterval: z.number().int().nonnegative(), MaximumAttempts: z.number().int().nonnegative(), TotalDuration: z.number().int().nonnegative() }).optional(),
42
+ executeDurability: z.number().int()
77
43
  });
78
- var QueryDefinitionWireSchema = z2.strictObject({ operation: OperationRefSchema, branches: z2.array(BranchDefinitionSchema).nullable(), stepDefaults: StepDefaultsWireSchema });
44
+ var QueryDefinitionWireSchema = z.strictObject({ operation: OperationRefSchema, branches: z.array(BranchDefinitionSchema).nullable(), stepDefaults: StepDefaultsWireSchema });
79
45
  var MutationDefinitionWireSchema = QueryDefinitionWireSchema;
80
- var ReceiptSchema = z2.strictObject({
46
+ var ReceiptSchema = z.strictObject({
81
47
  callId: CallIDSchema,
82
- idempotencyKey: z2.string().optional(),
83
- provider: z2.string().min(1),
84
- providerObjectId: z2.string().optional(),
85
- providerRequestId: z2.string().optional(),
86
- observedAt: z2.iso.datetime({ offset: true }),
87
- metadata: z2.record(z2.string(), z2.string()).optional()
48
+ idempotencyKey: z.string().optional(),
49
+ provider: z.string().min(1),
50
+ providerObjectId: z.string().optional(),
51
+ providerRequestId: z.string().optional(),
52
+ observedAt: z.iso.datetime({ offset: true }),
53
+ metadata: z.record(z.string(), z.string()).optional()
88
54
  });
89
55
  function zeroReceipt() {
90
56
  return { callId: "", provider: "", observedAt: "0001-01-01T00:00:00Z" };
91
57
  }
92
- var QueryResultSchema = (valueSchema) => z2.strictObject({ branch: z2.string().min(1), value: valueSchema, receipt: ReceiptSchema, failure: FailureSchema.optional() });
58
+ var QueryResultSchema = (valueSchema) => z.strictObject({ branch: z.string().min(1), value: valueSchema, receipt: ReceiptSchema, failure: FailureSchema.optional() });
93
59
  var MutationResultSchema = QueryResultSchema;
94
60
  function newQueryBranch(branch, value, receipt = {}, failure) {
95
61
  return failure === void 0 ? { kind: "branch", branch, value, receipt } : { kind: "branch", branch, value, receipt, failure };
@@ -119,36 +85,32 @@ function retryPolicyToGoWire(policy) {
119
85
  TotalDuration: policy.totalDurationMs * 1e6
120
86
  };
121
87
  }
122
- var ConnectorUIBindingSchema = z2.strictObject({ port: z2.string().regex(/^[a-z][A-Za-z0-9]*$/), jsonPointer: z2.string().regex(/^\/(?:[^~]|~[01])*$/) });
123
- var ConnectorUIUnitSchema = z2.strictObject({
124
- id: z2.string().regex(/^[a-z][A-Za-z0-9]*$/),
125
- unitId: z2.string().regex(/^[a-z][A-Za-z0-9]*$/),
126
- label: z2.string().refine((value) => value.trim().length > 0),
127
- description: z2.string().refine((value) => value.trim().length > 0),
128
- required: z2.boolean(),
129
- bindings: z2.array(ConnectorUIBindingSchema).min(1)
88
+ var ConnectorUIBindingSchema = z.strictObject({ port: z.string().regex(/^[a-z][A-Za-z0-9]*$/), jsonPointer: z.string().regex(/^\/(?:[^~]|~[01])*$/) });
89
+ var ConnectorUIUnitSchema = z.strictObject({
90
+ id: z.string().regex(/^[a-z][A-Za-z0-9]*$/),
91
+ unitId: z.string().regex(/^[a-z][A-Za-z0-9]*$/),
92
+ label: z.string().refine((value) => value.trim().length > 0),
93
+ description: z.string().refine((value) => value.trim().length > 0),
94
+ required: z.boolean(),
95
+ bindings: z.array(ConnectorUIBindingSchema).min(1)
130
96
  }).superRefine((unit, context) => {
131
97
  if (new Set(unit.bindings.map((binding) => binding.port)).size !== unit.bindings.length) context.addIssue({ code: "custom", message: "duplicate UI port" });
132
98
  });
133
- var ConnectorConfigurationUISchema = z2.strictObject({ units: z2.array(ConnectorUIUnitSchema) }).superRefine((ui, context) => {
99
+ var ConnectorConfigurationUISchema = z.strictObject({ units: z.array(ConnectorUIUnitSchema) }).superRefine((ui, context) => {
134
100
  if (new Set(ui.units.map((unit) => unit.id)).size !== ui.units.length) context.addIssue({ code: "custom", message: "duplicate UI unit ID" });
135
101
  });
136
- var ConnectorConfigurationRefSchema = z2.strictObject({
102
+ var ConnectorConfigurationRefSchema = z.strictObject({
137
103
  connectorId: OperationRefSchema.shape.connectorId,
138
- connectionName: z2.string().refine((value) => value.trim().length > 0),
104
+ connectionName: z.string().refine((value) => value.trim().length > 0),
139
105
  operationId: OperationRefSchema.shape.operationId,
140
- flowType: z2.string().refine((value) => value.trim().length > 0),
141
- stepType: z2.string().refine((value) => value.trim().length > 0)
106
+ flowType: z.string().refine((value) => value.trim().length > 0),
107
+ stepType: z.string().refine((value) => value.trim().length > 0)
142
108
  });
143
109
  function validateRetryDelay(delayMs) {
144
110
  if (!Number.isSafeInteger(delayMs) || delayMs < 0) throw new RangeError("retry delay must be a non-negative integer in milliseconds");
145
111
  }
146
112
 
147
113
  export {
148
- FailureKindSchema,
149
- FailureSchema,
150
- RetryError,
151
- ReauthorizationRequiredError,
152
114
  CallIDSchema,
153
115
  CallIDNamespace,
154
116
  ConnectionRefSchema,
@@ -0,0 +1,44 @@
1
+ // src/errors.ts
2
+ import { z } from "zod";
3
+ var FailureKindSchema = z.enum([
4
+ "VALIDATION",
5
+ "AUTHENTICATION",
6
+ "AUTHORIZATION",
7
+ "NOT_FOUND",
8
+ "CONFLICT",
9
+ "RATE_LIMIT",
10
+ "QUOTA_EXHAUSTED",
11
+ "AVAILABILITY",
12
+ "PROVIDER_REJECTION",
13
+ "TRANSPORT",
14
+ "RESPONSE_TOO_LARGE",
15
+ "PROTOCOL",
16
+ "LOCAL_DEFECT"
17
+ ]);
18
+ var FailureSchema = z.strictObject({ kind: FailureKindSchema, provider: z.string().min(1), operation: z.string().min(1), message: z.string().min(1) });
19
+ var RetryError = class extends Error {
20
+ /** Validated provider fact behind the retry request. */
21
+ failure;
22
+ /** Provider-requested retry delay in milliseconds; zero uses the Step policy. */
23
+ retryAfterMs;
24
+ constructor(failure, retryAfterMs = 0) {
25
+ const validated = FailureSchema.parse(failure);
26
+ super(`connector ${validated.provider} ${validated.operation} retry (${validated.kind}): ${validated.message}`);
27
+ this.name = "RetryError";
28
+ this.failure = validated;
29
+ this.retryAfterMs = retryAfterMs;
30
+ }
31
+ };
32
+ var ReauthorizationRequiredError = class extends Error {
33
+ constructor() {
34
+ super("connector reauthorization is required");
35
+ this.name = "ReauthorizationRequiredError";
36
+ }
37
+ };
38
+
39
+ export {
40
+ FailureKindSchema,
41
+ FailureSchema,
42
+ RetryError,
43
+ ReauthorizationRequiredError
44
+ };
@@ -0,0 +1,316 @@
1
+ import {
2
+ validateMutationDefinition,
3
+ validateQueryDefinition
4
+ } from "./chunk-32YJXBE4.js";
5
+ import {
6
+ createCall
7
+ } from "./chunk-QDMBAWXD.js";
8
+ import {
9
+ CallIDSchema,
10
+ ConnectionRefSchema,
11
+ ConnectorConfigurationUISchema,
12
+ DefectBranchID,
13
+ OperationRefSchema,
14
+ ReceiptSchema,
15
+ UncertainBranchID,
16
+ defaultConnectorStepExecuteRetryPolicy
17
+ } from "./chunk-BQGYGCOQ.js";
18
+ import {
19
+ FailureSchema,
20
+ RetryError
21
+ } from "./chunk-IHG6ADQG.js";
22
+
23
+ // src/run_operation.ts
24
+ async function runQuery(operation, call, input) {
25
+ if (!operation) return defectResult(void 0, call, "connector query is required");
26
+ const definition = operation.definition();
27
+ try {
28
+ validateQueryDefinition(definition);
29
+ } catch (error) {
30
+ return defectResult(definition, call, `invalid query definition: ${safeErrorMessage(error)}`);
31
+ }
32
+ const invalidCall = validateCall(call, definition.operation);
33
+ if (invalidCall) return defectResult(definition, call, invalidCall);
34
+ const attempt = await operation.invoke(call, input);
35
+ return resultFromAttempt(definition, call, attempt, "query");
36
+ }
37
+ async function runMutation(operation, call, input) {
38
+ if (!operation) return defectResult(void 0, call, "connector mutation is required");
39
+ const definition = operation.definition();
40
+ try {
41
+ validateMutationDefinition(definition);
42
+ } catch (error) {
43
+ return defectResult(definition, call, `invalid mutation definition: ${safeErrorMessage(error)}`);
44
+ }
45
+ const invalidCall = validateCall(call, definition.operation);
46
+ if (invalidCall) return defectResult(definition, call, invalidCall);
47
+ const chosenKey = operation.idempotencyKey(call.id, input) || call.id;
48
+ if (!chosenKey.trim()) return defectResult(definition, call, "mutation returned an invalid idempotency key");
49
+ const mutationCall = { ...call, context: call.context, idempotencyKey: chosenKey };
50
+ Object.defineProperty(mutationCall, "context", { value: call.context, enumerable: false });
51
+ for (const method of ["reportProgress", "writeText", "hasProgressStream", "hasTextStream"]) Object.defineProperty(mutationCall, method, { value: call[method], enumerable: false });
52
+ const attempt = await operation.invoke(mutationCall, input);
53
+ return resultFromAttempt(definition, mutationCall, attempt, "mutation");
54
+ }
55
+ function resultFromAttempt(definition, call, attempt, operationKind) {
56
+ if (!attempt || typeof attempt !== "object") return defectResult(definition, call, `${operationKind} returned an invalid attempt`);
57
+ if (attempt.kind === "retry") {
58
+ const failure = FailureSchema.safeParse(attempt.failure);
59
+ if (!failure.success || !Number.isSafeInteger(attempt.retryAfterMs) || attempt.retryAfterMs < 0) return defectResult(definition, call, `${operationKind} returned an invalid retry attempt`);
60
+ throw new RetryError(failure.data, attempt.retryAfterMs);
61
+ }
62
+ if (attempt.kind === "branch" || operationKind === "mutation" && attempt.kind === "uncertain") {
63
+ const branch = attempt.kind === "uncertain" ? UncertainBranchID : attempt.branch;
64
+ if (!definition.branches.some((declared) => declared.id === branch)) {
65
+ return defectResult(definition, call, attempt.kind === "uncertain" ? "mutation returned uncertainty without declaring the uncertain branch" : `${operationKind} returned an unknown branch`);
66
+ }
67
+ const failure = "failure" in attempt && attempt.failure !== void 0 ? FailureSchema.safeParse(attempt.failure) : void 0;
68
+ if (failure && !failure.success) return defectResult(definition, call, `${operationKind} returned an invalid failure`);
69
+ if (attempt.kind === "uncertain" && !failure) return defectResult(definition, call, "mutation returned an invalid uncertainty failure");
70
+ let receipt;
71
+ try {
72
+ receipt = completeReceipt(attempt.receipt, call);
73
+ } catch (error) {
74
+ return defectResult(definition, call, safeErrorMessage(error));
75
+ }
76
+ const result = { branch, value: attempt.value, receipt };
77
+ if (failure?.success) result.failure = failure.data;
78
+ return result;
79
+ }
80
+ return defectResult(definition, call, `${operationKind} returned an invalid attempt`);
81
+ }
82
+ function completeReceipt(draft, call) {
83
+ if (draft.callId && draft.callId !== call.id) throw new TypeError("operation returned a receipt for another call");
84
+ if (draft.idempotencyKey && draft.idempotencyKey !== call.idempotencyKey) throw new TypeError("operation returned a receipt with another idempotency key");
85
+ return ReceiptSchema.parse({ ...draft, callId: call.id, ...call.idempotencyKey ? { idempotencyKey: call.idempotencyKey } : {}, provider: draft.provider || call.operation.connectorId, observedAt: draft.observedAt && draft.observedAt !== "0001-01-01T00:00:00Z" ? draft.observedAt : (/* @__PURE__ */ new Date()).toISOString() });
86
+ }
87
+ function validateCall(call, operation) {
88
+ if (!call) return "connector call is required";
89
+ if (!CallIDSchema.safeParse(call.id).success) return "call ID must be a UUID";
90
+ if (!ConnectionRefSchema.safeParse(call.connection).success) return "connection provider and name are required";
91
+ if (!OperationRefSchema.safeParse(call.operation).success || call.operation.connectorId !== operation.connectorId || call.operation.operationId !== operation.operationId) return "connector call operation does not match the definition";
92
+ return void 0;
93
+ }
94
+ function defectResult(definition, call, message) {
95
+ const operation = definition?.operation;
96
+ const failure = { kind: "LOCAL_DEFECT", provider: operation?.connectorId || "connector", operation: operation?.operationId || "invoke", message };
97
+ const receipt = call && CallIDSchema.safeParse(call.id).success ? completeReceipt({}, call) : void 0;
98
+ return { branch: DefectBranchID, value: void 0, receipt, failure };
99
+ }
100
+ function safeErrorMessage(error) {
101
+ return error instanceof Error ? error.message : "invalid value";
102
+ }
103
+
104
+ // src/step.ts
105
+ import { StepRef, forceFail, goTo, retryAfter } from "@superdurable/dex";
106
+ function goToBranch(branch, target) {
107
+ return target ? { branch, target } : { branch };
108
+ }
109
+ function stepRef(stepType) {
110
+ return new StepRef(stepType);
111
+ }
112
+ var QueryStep = class {
113
+ inputCodec;
114
+ #configuration;
115
+ #options;
116
+ #ui;
117
+ #targets;
118
+ #optional;
119
+ #identity;
120
+ /** Validate static wiring before registering the Step in a Flow. */
121
+ constructor(configuration) {
122
+ if (!configuration?.operation) throw new TypeError("query operation is required");
123
+ const definition = configuration.operation.definition();
124
+ validateQueryDefinition(definition);
125
+ validateFactoryConfiguration(configuration);
126
+ const routes = validateBranchTargets(definition.branches, configuration.branches);
127
+ this.#configuration = configuration;
128
+ this.#options = mergeStepOptions(definition.stepDefaults, configuration.stepOptionsOverride);
129
+ this.#ui = ConnectorConfigurationUISchema.parse(configuration.configurationUI ?? { units: [] });
130
+ this.#targets = routes.targets;
131
+ this.#optional = routes.optional;
132
+ this.#identity = { operation: definition.operation, connection: configuration.connection };
133
+ if (configuration.inputCodec) this.inputCodec = configuration.inputCodec;
134
+ }
135
+ /** Stable Dex Step type. */
136
+ getStepType() {
137
+ return this.#configuration.stepType;
138
+ }
139
+ /** Isolated Execute options, including connector retry defaults. */
140
+ getStepOptions() {
141
+ return cloneStepOptions(this.#options);
142
+ }
143
+ /** Group metadata for Connector Studio. */
144
+ annotations() {
145
+ return { ...this.#configuration.annotations };
146
+ }
147
+ /** Isolated connector UI composition. */
148
+ configurationUI() {
149
+ return structuredClone(this.#ui);
150
+ }
151
+ /** Invoke, persist the optional terminal Attribute, and route the selected branch. */
152
+ async execute(context, input) {
153
+ const operationInput = this.#configuration.mapToOperationInput(input);
154
+ const call = createCall(context, this.#identity.connection, this.#identity.operation, {
155
+ ...this.#configuration.progressStream ? { progressStream: this.#configuration.progressStream } : {},
156
+ ...this.#configuration.textStream ? { textStream: this.#configuration.textStream } : {},
157
+ ...this.#configuration.textOptions ? { textOptions: this.#configuration.textOptions } : {}
158
+ });
159
+ let result;
160
+ try {
161
+ result = await runQuery(this.#configuration.operation, call, operationInput);
162
+ } catch (error) {
163
+ throwDexRetry(error);
164
+ }
165
+ if (this.#configuration.resultAttribute) context.setAttribute(this.#configuration.resultAttribute, result);
166
+ return routeBranch(this.#targets, this.#optional, result, this.#identity, "query");
167
+ }
168
+ };
169
+ var MutationStep = class {
170
+ inputCodec;
171
+ #configuration;
172
+ #options;
173
+ #ui;
174
+ #targets;
175
+ #optional;
176
+ #identity;
177
+ /** Validate static wiring before registering the Step in a Flow. */
178
+ constructor(configuration) {
179
+ if (!configuration?.operation) throw new TypeError("mutation operation is required");
180
+ const definition = configuration.operation.definition();
181
+ validateMutationDefinition(definition);
182
+ validateFactoryConfiguration(configuration);
183
+ const routes = validateBranchTargets(definition.branches, configuration.branches);
184
+ this.#configuration = configuration;
185
+ this.#options = mergeStepOptions(definition.stepDefaults, configuration.stepOptionsOverride);
186
+ this.#ui = ConnectorConfigurationUISchema.parse(configuration.configurationUI ?? { units: [] });
187
+ this.#targets = routes.targets;
188
+ this.#optional = routes.optional;
189
+ this.#identity = { operation: definition.operation, connection: configuration.connection };
190
+ if (configuration.inputCodec) this.inputCodec = configuration.inputCodec;
191
+ }
192
+ /** Stable Dex Step type. */
193
+ getStepType() {
194
+ return this.#configuration.stepType;
195
+ }
196
+ /** Isolated Execute options, including connector retry defaults. */
197
+ getStepOptions() {
198
+ return cloneStepOptions(this.#options);
199
+ }
200
+ /** Group metadata for Connector Studio. */
201
+ annotations() {
202
+ return { ...this.#configuration.annotations };
203
+ }
204
+ /** Isolated connector UI composition. */
205
+ configurationUI() {
206
+ return structuredClone(this.#ui);
207
+ }
208
+ /** Invoke, persist the optional terminal Attribute, and route the selected branch. */
209
+ async execute(context, input) {
210
+ const operationInput = this.#configuration.mapToOperationInput(input);
211
+ const call = createCall(context, this.#identity.connection, this.#identity.operation, {
212
+ ...this.#configuration.progressStream ? { progressStream: this.#configuration.progressStream } : {},
213
+ ...this.#configuration.textStream ? { textStream: this.#configuration.textStream } : {},
214
+ ...this.#configuration.textOptions ? { textOptions: this.#configuration.textOptions } : {}
215
+ });
216
+ let result;
217
+ try {
218
+ result = await runMutation(this.#configuration.operation, call, operationInput);
219
+ } catch (error) {
220
+ throwDexRetry(error);
221
+ }
222
+ if (this.#configuration.resultAttribute) context.setAttribute(this.#configuration.resultAttribute, result);
223
+ return routeBranch(this.#targets, this.#optional, result, this.#identity, "mutation");
224
+ }
225
+ };
226
+ function newQueryStep(configuration) {
227
+ return new QueryStep(configuration);
228
+ }
229
+ function newMutationStep(configuration) {
230
+ return new MutationStep(configuration);
231
+ }
232
+ function validateFactoryConfiguration(configuration) {
233
+ if (!configuration.stepType?.trim()) throw new TypeError("stable Step type is required");
234
+ if (!/^[a-z][a-z0-9-]*$/.test(configuration.annotations?.groupId ?? "") || !configuration.annotations.groupLabel?.trim() || !configuration.annotations.explanation?.trim()) throw new TypeError("Step group, group label, and explanation are required");
235
+ ConnectionRefSchema.parse(configuration.connection);
236
+ if (typeof configuration.mapToOperationInput !== "function") throw new TypeError("mapToOperationInput is required");
237
+ }
238
+ function validateBranchTargets(definitions, routes) {
239
+ const expected = new Map(definitions.map((branch) => [branch.id, branch]));
240
+ const targets = /* @__PURE__ */ new Map();
241
+ const optional = new Set(definitions.filter((branch) => branch.optional).map((branch) => branch.id));
242
+ for (const route of routes) {
243
+ if (!expected.has(route.branch)) throw new TypeError(`branch target ${route.branch} is not declared by the operation`);
244
+ if (!route.target) {
245
+ if (!optional.has(route.branch)) throw new TypeError(`branch target ${route.branch} must name a Step`);
246
+ continue;
247
+ }
248
+ if (route.target instanceof StepRef && !route.target.stepType.trim()) throw new TypeError(`branch target ${route.branch} must name a Step`);
249
+ if (typeof route.target === "object" && !(route.target instanceof StepRef) && !route.target.getStepType().trim()) throw new TypeError(`branch target ${route.branch} must name a Step`);
250
+ if (targets.has(route.branch)) throw new TypeError(`branch target ${route.branch} is duplicated`);
251
+ targets.set(route.branch, route.target);
252
+ }
253
+ for (const branch of definitions) if (!branch.optional && !targets.has(branch.id)) throw new TypeError(`branch target ${branch.id} is required`);
254
+ return { targets, optional };
255
+ }
256
+ function mergeStepOptions(defaults, override) {
257
+ if (override && Object.keys(override).some((key) => key.startsWith("waitFor") && override[key] !== void 0)) throw new TypeError("execute-only connector Step rejects WaitFor options");
258
+ const merged = {
259
+ ...override?.executeMethodTimeoutMs || defaults.executeMethodTimeoutMs ? { executeMethodTimeoutMs: override?.executeMethodTimeoutMs || defaults.executeMethodTimeoutMs } : {},
260
+ ...override?.heartbeatTimeoutMs || defaults.heartbeatTimeoutMs ? { heartbeatTimeoutMs: override?.heartbeatTimeoutMs || defaults.heartbeatTimeoutMs } : {},
261
+ executeRetry: { ...override?.executeRetry ?? defaults.executeRetry ?? defaultConnectorStepExecuteRetryPolicy() },
262
+ ...override?.executeDurability || (defaults.executeDurability !== "default" ? defaults.executeDurability : void 0) ? { executeDurability: override?.executeDurability ?? defaults.executeDurability } : {},
263
+ ...override?.executeFailure ? { executeFailure: override.executeFailure } : {},
264
+ ...override?.executeLockAttributes ? { executeLockAttributes: override.executeLockAttributes } : {},
265
+ ...override?.executeLoadAttributeMaps ? { executeLoadAttributeMaps: override.executeLoadAttributeMaps } : {},
266
+ ...override?.executeLoadAttributeMapInstances ? { executeLoadAttributeMapInstances: override.executeLoadAttributeMapInstances } : {},
267
+ ...override?.executeLoadChannels ? { executeLoadChannels: override.executeLoadChannels } : {},
268
+ ...override?.executeLoadChannelMaps ? { executeLoadChannelMaps: override.executeLoadChannelMaps } : {},
269
+ ...override?.executeLoadChannelMapInstances ? { executeLoadChannelMapInstances: override.executeLoadChannelMapInstances } : {}
270
+ };
271
+ return cloneStepOptions(merged);
272
+ }
273
+ function cloneStepOptions(options) {
274
+ return {
275
+ ...options,
276
+ ...options.executeRetry ? { executeRetry: { ...options.executeRetry } } : {},
277
+ ...options.executeLockAttributes ? { executeLockAttributes: [...options.executeLockAttributes] } : {},
278
+ ...options.executeLoadAttributeMaps ? { executeLoadAttributeMaps: [...options.executeLoadAttributeMaps] } : {},
279
+ ...options.executeLoadAttributeMapInstances ? { executeLoadAttributeMapInstances: [...options.executeLoadAttributeMapInstances] } : {},
280
+ ...options.executeLoadChannels ? { executeLoadChannels: [...options.executeLoadChannels] } : {},
281
+ ...options.executeLoadChannelMaps ? { executeLoadChannelMaps: [...options.executeLoadChannelMaps] } : {},
282
+ ...options.executeLoadChannelMapInstances ? { executeLoadChannelMapInstances: [...options.executeLoadChannelMapInstances] } : {}
283
+ };
284
+ }
285
+ function routeBranch(targets, optional, result, identity, operationKind) {
286
+ const target = targets.get(result.branch);
287
+ if (target) return goTo(target, result);
288
+ if (optional.has(result.branch)) {
289
+ let reason = `${identity.operation.connectorId} ${identity.operation.operationId} (connection ${identity.connection.name}) selected branch ${result.branch} with no target`;
290
+ if (result.failure) reason += `: ${result.failure.kind}: ${boundedFailureMessage(result.failure.message)}`;
291
+ return forceFail(reason);
292
+ }
293
+ throw new TypeError(`${operationKind} result selected unconfigured branch ${result.branch}`);
294
+ }
295
+ function boundedFailureMessage(message) {
296
+ const bytes = Buffer.from(message);
297
+ if (bytes.length <= 1024) return message;
298
+ let end = 1024;
299
+ while (end > 0 && (bytes[end] & 192) === 128) end--;
300
+ return `${bytes.subarray(0, end).toString("utf8")} (truncated)`;
301
+ }
302
+ function throwDexRetry(error) {
303
+ if (error instanceof RetryError && error.retryAfterMs >= 1e3) throw retryAfter(Math.floor(error.retryAfterMs / 1e3), error);
304
+ throw error;
305
+ }
306
+
307
+ export {
308
+ runQuery,
309
+ runMutation,
310
+ goToBranch,
311
+ stepRef,
312
+ QueryStep,
313
+ MutationStep,
314
+ newQueryStep,
315
+ newMutationStep
316
+ };
@@ -2,7 +2,7 @@ import {
2
2
  ConnectionRefSchema,
3
3
  OperationRefSchema,
4
4
  deriveCallID
5
- } from "./chunk-SOXYPIMO.js";
5
+ } from "./chunk-BQGYGCOQ.js";
6
6
 
7
7
  // src/credentials.ts
8
8
  function createCall(context, connection, operation, options = {}) {
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
- import { F as Failure, B as BranchID, C as Call, M as MutationAttempt, Q as QueryAttempt, U as UncertainBranchID, a as CallID } from '../credentials-vrvW0d4j.js';
3
- import { Q as QueryDefinition, M as Mutation, a as MutationDefinition, b as Query } from '../operation-Ca8rfacf.js';
2
+ import { F as Failure, B as BranchID, M as MutationAttempt, Q as QueryAttempt, U as UncertainBranchID, C as CallID } from '../types-D6De3sry.js';
3
+ import { C as Call } from '../credentials-JqG97kJ5.js';
4
+ import { Q as QueryDefinition, M as Mutation, a as MutationDefinition, b as Query } from '../operation-CASLOg86.js';
4
5
  import '@superdurable/dex';
5
6
 
6
7
  /** One answered mock call, including input only in test memory. */
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  validateMutationDefinition,
3
3
  validateQueryDefinition
4
- } from "../chunk-2NBM7P4T.js";
4
+ } from "../chunk-32YJXBE4.js";
5
5
  import {
6
6
  DefectBranchID,
7
- FailureSchema,
8
7
  UncertainBranchID,
9
8
  newMutationBranch,
10
9
  newMutationRetry,
@@ -12,7 +11,10 @@ import {
12
11
  newQueryBranch,
13
12
  newQueryRetry,
14
13
  zeroReceipt
15
- } from "../chunk-SOXYPIMO.js";
14
+ } from "../chunk-BQGYGCOQ.js";
15
+ import {
16
+ FailureSchema
17
+ } from "../chunk-IHG6ADQG.js";
16
18
 
17
19
  // src/connectormock/index.ts
18
20
  import { readFile } from "fs/promises";
@@ -0,0 +1,102 @@
1
+ import { C as CallID, d as ConnectionRef, O as OperationRef } from './types-D6De3sry.js';
2
+ import { AsyncContext, Stream, BufferedTextStreamOptions } from '@superdurable/dex';
3
+
4
+ /** Provider-safe progress before Dex identity and sequence are added. */
5
+ interface Progress {
6
+ /** Provider-specific stable phase. */ phase: string;
7
+ /** Optional safe progress text. */ message?: string;
8
+ /** Optional inclusive fraction from zero to one. */ percent?: number;
9
+ /** Optional provider-owned monotonic sequence. */ providerSequence?: number;
10
+ }
11
+ /** Structured best-effort Dex Stream message. */
12
+ interface ProgressUpdate extends Progress {
13
+ /** Stable connector call ID. */ callId: CallID;
14
+ /** One-based Dex Execute attempt. */ attempt: number;
15
+ /** Connector-assigned monotonic sequence within this attempt. */ sequence: number;
16
+ }
17
+ /** Optional application-owned Streams for one connector invocation. */
18
+ interface CallProgressOptions {
19
+ /** Registered structured progress Stream. */ progressStream?: Stream<ProgressUpdate>;
20
+ /** Registered string Stream for ordered buffered text. */ textStream?: Stream<string>;
21
+ /** Flush interval and soft UTF-8 batch limit for text. */ textOptions?: BufferedTextStreamOptions;
22
+ }
23
+ /** Provider-safe call metadata with its live, non-serializable Dex Step context. */
24
+ interface Call {
25
+ /** Active Dex Execute context; Step factories attach it as a non-enumerable field. */ context: AsyncContext;
26
+ /** Stable identity across retries. */ id: CallID;
27
+ /** Provider deduplication key, when available. */ idempotencyKey?: string;
28
+ /** Logical named connection. */ connection: ConnectionRef;
29
+ /** Manifest operation identity. */ operation: OperationRef;
30
+ /** Append structured progress when a Stream is configured. */ reportProgress(progress: Progress): void;
31
+ /** Append text in order when a buffered Stream is configured. */ writeText(value: string): void;
32
+ /** Whether structured progress output is configured. */ hasProgressStream(): boolean;
33
+ /** Whether buffered text output is configured. */ hasTextStream(): boolean;
34
+ }
35
+ /** Bind a live Dex Execute context to a stable, provider-safe call identity. */
36
+ declare function createCall(context: AsyncContext, connection: ConnectionRef, operation: OperationRef, options?: CallProgressOptions): Call;
37
+ /** Resolve a credential at call time outside durable Flow state. */
38
+ interface CredentialProvider<C> {
39
+ /** Return current credentials, honoring cancellation. */
40
+ resolve(call: Call, signal?: AbortSignal): Promise<C>;
41
+ }
42
+ /** Resolve credentials outside a Dex Step, such as for a Trigger source. */
43
+ interface ContextCredentialProvider<C> extends CredentialProvider<C> {
44
+ /** Return current credentials under an explicit cancellation signal. */
45
+ resolveContext(call: Call, signal: AbortSignal): Promise<C>;
46
+ }
47
+ /** Current private material and decision time for a refresh driver. */
48
+ interface CredentialRefreshState<C> {
49
+ /** Current connector-specific credential. */ credentials: C;
50
+ /** Known access credential expiry. */ expiresAt?: Date;
51
+ /** Captured decision time. */ now: Date;
52
+ }
53
+ /** Complete replacement credential and mandatory access expiry. */
54
+ interface CredentialRefreshResult<C> {
55
+ /** Complete replacement, retaining omitted renewal material. */ credentials: C;
56
+ /** Replacement access expiry. */ expiresAt: Date;
57
+ }
58
+ /** Connector-specific provider refresh contract; persistence belongs to the host. */
59
+ interface CredentialRefreshDriver<C> {
60
+ /** Decide deterministically whether a credential needs provider renewal. */
61
+ refreshRequired(state: CredentialRefreshState<C>): boolean;
62
+ /** Make one provider refresh request after the host admits it durably. */
63
+ refresh(state: CredentialRefreshState<C>, signal: AbortSignal): Promise<CredentialRefreshResult<C>>;
64
+ }
65
+ /** Host adapter that refreshes and persists a connection atomically. */
66
+ interface RefreshingCredentialProvider<C> extends CredentialProvider<C> {
67
+ /** Serialize refresh for one connection, reload state, and persist replacement. */
68
+ resolveWithRefresh(call: Call, driver: CredentialRefreshDriver<C>, signal?: AbortSignal): Promise<C>;
69
+ }
70
+ /** Host adapter for one explicit provider authentication rejection. */
71
+ interface RejectedCredentialRefreshingProvider<C> {
72
+ /** Force one coordinated refresh after the provider rejects an access token. */
73
+ resolveAfterRejection(call: Call, driver: CredentialRefreshDriver<C>, signal?: AbortSignal): Promise<C>;
74
+ }
75
+ /** Resolve through host refresh support, then context-aware or ordinary lookup. */
76
+ declare function resolveCredential<C>(provider: CredentialProvider<C>, call: Call, driver: CredentialRefreshDriver<C>, signal?: AbortSignal): Promise<C>;
77
+ /** Force one coordinated refresh after a provider authentication rejection. */
78
+ declare function resolveCredentialAfterRejection<C>(provider: CredentialProvider<C>, call: Call, driver: CredentialRefreshDriver<C>, signal?: AbortSignal): Promise<C>;
79
+ /** In-memory named credentials for examples and tests; never persisted by this class. */
80
+ declare class StaticCredentialProvider<C> implements RefreshingCredentialProvider<C> {
81
+ #private;
82
+ /** Capture all connection values during construction. */
83
+ constructor(entries: Iterable<readonly [ConnectionRef, C]>);
84
+ /** Return the configured credential or reject a missing connection. */
85
+ resolve(call: Call): Promise<C>;
86
+ /** Static credentials never expire and therefore do not call the driver. */
87
+ resolveWithRefresh(call: Call): Promise<C>;
88
+ }
89
+ /** Wrap a secret that cannot be serialized or printed. */
90
+ declare class SecretString {
91
+ #private;
92
+ /** Hold one private value outside default stringification and inspection. */
93
+ constructor(value: string);
94
+ /** Reveal only at the provider request boundary. */
95
+ reveal(): string;
96
+ /** Return a fixed redaction for accidental string formatting. */
97
+ toString(): string;
98
+ /** Reject accidental JSON persistence. */
99
+ toJSON(): never;
100
+ }
101
+
102
+ export { type Call as C, type ProgressUpdate as P, type RefreshingCredentialProvider as R, SecretString as S, type CallProgressOptions as a, type ContextCredentialProvider as b, type CredentialProvider as c, type CredentialRefreshDriver as d, type CredentialRefreshResult as e, type CredentialRefreshState as f, type Progress as g, type RejectedCredentialRefreshingProvider as h, StaticCredentialProvider as i, createCall as j, resolveCredentialAfterRejection as k, resolveCredential as r };