@sanity/workflow-engine 0.19.0 → 0.20.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/CHANGELOG.md +103 -0
- package/dist/_chunks-cjs/invariants.cjs +52 -12
- package/dist/_chunks-es/invariants.js +52 -12
- package/dist/define.d.cts +20 -26
- package/dist/define.d.ts +20 -26
- package/dist/index.cjs +289 -103
- package/dist/index.d.cts +90 -66
- package/dist/index.d.ts +90 -66
- package/dist/index.js +287 -105
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -4016,12 +4016,27 @@ function assertInputValueShape(entry, value) {
|
|
|
4016
4016
|
function assertGdrShape(value, context) {
|
|
4017
4017
|
if (typeof value != "object" || value === null) throw new invariants.ContractViolationError(`Invalid GDR for ${context}: expected { id: "<scheme>:...", type: "<schema>" }, got ${typeof value}.`);
|
|
4018
4018
|
const v2 = value;
|
|
4019
|
-
if (typeof v2.id != "string"
|
|
4019
|
+
if (typeof v2.id != "string") throw invalidGdrUriError(context, v2.id);
|
|
4020
|
+
try {
|
|
4021
|
+
invariants.parseGdr(v2.id);
|
|
4022
|
+
} catch (error) {
|
|
4023
|
+
throw error instanceof invariants.VersionSpecificDatasetGdrError ? new invariants.ContractViolationError(`Invalid GDR for ${context}: ${error.message}`) : invalidGdrUriError(context, v2.id);
|
|
4024
|
+
}
|
|
4020
4025
|
if (typeof v2.type != "string" || v2.type.length === 0) throw new invariants.ContractViolationError(`Invalid GDR for ${context}: \`type\` (schema name) must be a non-empty string. Got ${JSON.stringify(v2.type)}.`);
|
|
4021
4026
|
}
|
|
4022
4027
|
|
|
4028
|
+
function invalidGdrUriError(context, id) {
|
|
4029
|
+
return new invariants.ContractViolationError(`Invalid GDR for ${context}: \`id\` must be a GDR URI ("<scheme>:<...id-parts>" with scheme dataset|canvas|media-library|dashboard). Got ${JSON.stringify(id)}. Construct via \`gdrFromResource\` / \`refDataset\` / \`refCanvas\` etc. — bare document ids are not accepted.`);
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4023
4032
|
function normalizeQueryResult({entryType: entryType, raw: raw, workflowResource: workflowResource}) {
|
|
4024
|
-
|
|
4033
|
+
if (raw == null) return raw;
|
|
4034
|
+
try {
|
|
4035
|
+
return invariants.isSingleDocRefKind(entryType) ? coerceToGdr(raw, workflowResource) : entryType === "doc.refs" ? Array.isArray(raw) ? raw.map(item => coerceToGdr(item, workflowResource)).filter(v2 => v2 !== null) : [] : raw;
|
|
4036
|
+
} catch (error) {
|
|
4037
|
+
if (error instanceof invariants.VersionSpecificDatasetGdrError) return raw;
|
|
4038
|
+
throw error;
|
|
4039
|
+
}
|
|
4025
4040
|
}
|
|
4026
4041
|
|
|
4027
4042
|
function coerceGdrShape(raw, workflowResource) {
|
|
@@ -4477,65 +4492,119 @@ function buildInstanceBase(args) {
|
|
|
4477
4492
|
}
|
|
4478
4493
|
|
|
4479
4494
|
async function hydrateSnapshot(args) {
|
|
4480
|
-
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set
|
|
4481
|
-
if (visited.has(uri)) return;
|
|
4482
|
-
const held = overlay?.get(uri);
|
|
4483
|
-
if (held !== void 0) {
|
|
4484
|
-
loaded.push(held), visited.add(uri);
|
|
4485
|
-
return;
|
|
4486
|
-
}
|
|
4487
|
-
const fetched = await loadByGdr({
|
|
4488
|
-
defaultClient: client,
|
|
4489
|
-
clientForGdr: clientForGdr,
|
|
4490
|
-
defaultResource: instance.workflowResource,
|
|
4491
|
-
uri: uri,
|
|
4492
|
-
perspective: perspective
|
|
4493
|
-
});
|
|
4494
|
-
fetched && (loaded.push(fetched), visited.add(uri));
|
|
4495
|
-
};
|
|
4495
|
+
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set;
|
|
4496
4496
|
loaded.push({
|
|
4497
4497
|
doc: instance,
|
|
4498
4498
|
resource: instance.workflowResource
|
|
4499
4499
|
}), visited.add(invariants.selfGdr(instance));
|
|
4500
|
-
|
|
4500
|
+
const {pending: pending, ordered: ordered} = planReads({
|
|
4501
|
+
client: client,
|
|
4502
|
+
clientForGdr: clientForGdr,
|
|
4503
|
+
instance: instance,
|
|
4504
|
+
overlay: overlay,
|
|
4505
|
+
visited: visited
|
|
4506
|
+
}), fetched = await readPending(pending);
|
|
4507
|
+
for (const entry of ordered) if (!isPendingRead(entry)) loaded.push(entry); else {
|
|
4508
|
+
const doc = fetched.get(entry);
|
|
4509
|
+
doc !== void 0 && loaded.push({
|
|
4510
|
+
doc: doc,
|
|
4511
|
+
resource: entry.resource
|
|
4512
|
+
});
|
|
4513
|
+
}
|
|
4501
4514
|
return buildSnapshot({
|
|
4502
4515
|
docs: loaded
|
|
4503
4516
|
});
|
|
4504
4517
|
}
|
|
4505
4518
|
|
|
4506
|
-
|
|
4507
|
-
const
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4519
|
+
function planReads(args) {
|
|
4520
|
+
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay, visited: visited} = args, pending = [], ordered = [];
|
|
4521
|
+
for (const ref of collectWatchRefs(instance)) {
|
|
4522
|
+
if (visited.has(ref.id)) continue;
|
|
4523
|
+
visited.add(ref.id);
|
|
4524
|
+
const held = overlay?.get(ref.id);
|
|
4525
|
+
if (held !== void 0) ordered.push(held); else {
|
|
4526
|
+
const read = routeRead({
|
|
4527
|
+
defaultClient: client,
|
|
4528
|
+
clientForGdr: clientForGdr,
|
|
4529
|
+
defaultResource: instance.workflowResource,
|
|
4530
|
+
uri: ref.id,
|
|
4531
|
+
perspective: readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE
|
|
4532
|
+
});
|
|
4533
|
+
pending.push(read), ordered.push(read);
|
|
4534
|
+
}
|
|
4518
4535
|
}
|
|
4519
|
-
|
|
4520
|
-
|
|
4536
|
+
return {
|
|
4537
|
+
pending: pending,
|
|
4538
|
+
ordered: ordered
|
|
4539
|
+
};
|
|
4540
|
+
}
|
|
4541
|
+
|
|
4542
|
+
function isPendingRead(entry) {
|
|
4543
|
+
return "client" in entry;
|
|
4544
|
+
}
|
|
4545
|
+
|
|
4546
|
+
const SNAPSHOT_READ_BATCH_SIZE = 100, SNAPSHOT_READ_CONCURRENCY = 4, snapshotDocsQuery = "*[_id in $ids]";
|
|
4547
|
+
|
|
4548
|
+
function routeRead({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
|
|
4549
|
+
const parsed = invariants.tryParseGdr(uri);
|
|
4550
|
+
return parsed === void 0 ? {
|
|
4551
|
+
client: defaultClient,
|
|
4552
|
+
id: uri,
|
|
4553
|
+
perspective: perspective,
|
|
4554
|
+
resource: defaultResource
|
|
4555
|
+
} : {
|
|
4556
|
+
client: clientForGdr(parsed),
|
|
4521
4557
|
id: parsed.documentId,
|
|
4522
|
-
perspective: perspective
|
|
4523
|
-
});
|
|
4524
|
-
return doc ? {
|
|
4525
|
-
doc: doc,
|
|
4558
|
+
perspective: perspective,
|
|
4526
4559
|
resource: invariants.resourceFromParsed(parsed)
|
|
4527
|
-
}
|
|
4560
|
+
};
|
|
4528
4561
|
}
|
|
4529
4562
|
|
|
4530
|
-
async function
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4563
|
+
async function readPending(reads) {
|
|
4564
|
+
const batches = groupReads(reads).flatMap(group => chunks(group.reads, SNAPSHOT_READ_BATCH_SIZE).map(batch => ({
|
|
4565
|
+
group: group,
|
|
4566
|
+
batch: batch
|
|
4567
|
+
}))), results = [];
|
|
4568
|
+
for (const wave of chunks(batches, SNAPSHOT_READ_CONCURRENCY)) results.push(...await Promise.all(wave.map(readBatch)));
|
|
4569
|
+
return new Map(results.flat());
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4572
|
+
async function readBatch(args) {
|
|
4573
|
+
const {group: group, batch: batch} = args, ids = batch.map(read => read.id), docs = await group.client.fetch(snapshotDocsQuery, {
|
|
4574
|
+
ids: ids
|
|
4575
|
+
}, {
|
|
4576
|
+
perspective: group.perspective
|
|
4577
|
+
}), byId = new Map(docs.map(doc => [ doc._id, validateRawDoc(doc, group.perspective) ]));
|
|
4578
|
+
return batch.flatMap(read => {
|
|
4579
|
+
const doc = byId.get(read.id);
|
|
4580
|
+
return doc === void 0 ? [] : [ [ read, doc ] ];
|
|
4581
|
+
});
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
function validateRawDoc(doc, perspective) {
|
|
4585
|
+
return perspective !== "raw" ? doc : doc._type === invariants.WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc) : invariants.assertReadableModel(doc);
|
|
4586
|
+
}
|
|
4587
|
+
|
|
4588
|
+
function groupReads(reads) {
|
|
4589
|
+
const byClient = /* @__PURE__ */ new Map;
|
|
4590
|
+
for (const read of reads) {
|
|
4591
|
+
let clientGroups = byClient.get(read.client);
|
|
4592
|
+
clientGroups === void 0 && (clientGroups = /* @__PURE__ */ new Map, byClient.set(read.client, clientGroups));
|
|
4593
|
+
const key = JSON.stringify(read.perspective);
|
|
4594
|
+
let group = clientGroups.get(key);
|
|
4595
|
+
group === void 0 && (group = {
|
|
4596
|
+
client: read.client,
|
|
4597
|
+
perspective: read.perspective,
|
|
4598
|
+
reads: []
|
|
4599
|
+
}, clientGroups.set(key, group)), group.reads.push(read);
|
|
4534
4600
|
}
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4601
|
+
return [ ...byClient.values() ].flatMap(groups => [ ...groups.values() ]);
|
|
4602
|
+
}
|
|
4603
|
+
|
|
4604
|
+
function chunks(values, size) {
|
|
4605
|
+
return Array.from({
|
|
4606
|
+
length: Math.ceil(values.length / size)
|
|
4607
|
+
}, (_, index) => values.slice(index * size, (index + 1) * size));
|
|
4539
4608
|
}
|
|
4540
4609
|
|
|
4541
4610
|
function collectEntryDocUris(resolvedFieldEntries) {
|
|
@@ -4939,7 +5008,7 @@ function unwrapPatch(patch) {
|
|
|
4939
5008
|
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
4940
5009
|
}
|
|
4941
5010
|
|
|
4942
|
-
const wrapperCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
5011
|
+
const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
4943
5012
|
|
|
4944
5013
|
function unwrapRequestTag(client) {
|
|
4945
5014
|
let current = client;
|
|
@@ -4956,6 +5025,30 @@ function withRequestTag(client, fallback) {
|
|
|
4956
5025
|
return byTag.set(fallback, wrapped), wrapped;
|
|
4957
5026
|
}
|
|
4958
5027
|
|
|
5028
|
+
function effectHandlerClient(client) {
|
|
5029
|
+
const cached = effectHandlerClientCache.get(client);
|
|
5030
|
+
if (cached !== void 0) return cached;
|
|
5031
|
+
let tagged;
|
|
5032
|
+
if (client.withConfig === void 0) tagged = withRequestTag(client, REQUEST_TAG.effect); else {
|
|
5033
|
+
const prefix = clientRequestTagPrefix(client), effectTag = composeRequestTag(prefix, REQUEST_TAG.effect);
|
|
5034
|
+
tagged = client.withConfig({
|
|
5035
|
+
requestTagPrefix: effectTag
|
|
5036
|
+
});
|
|
5037
|
+
}
|
|
5038
|
+
return effectHandlerClientCache.set(client, tagged), tagged;
|
|
5039
|
+
}
|
|
5040
|
+
|
|
5041
|
+
function effectHandlerResolver(resolver) {
|
|
5042
|
+
return mapResourceClientResolver(resolver, effectHandlerClient);
|
|
5043
|
+
}
|
|
5044
|
+
|
|
5045
|
+
function mapResourceClientResolver(resolver, mapClient) {
|
|
5046
|
+
if (resolver !== void 0) return parsed => {
|
|
5047
|
+
const client = resolver(parsed);
|
|
5048
|
+
return client === void 0 ? void 0 : mapClient(client);
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
|
|
4959
5052
|
function isWorkflowsFamilyPrefix(prefix) {
|
|
4960
5053
|
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
4961
5054
|
}
|
|
@@ -4965,8 +5058,18 @@ function clientRequestTagPrefix(client) {
|
|
|
4965
5058
|
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
4966
5059
|
}
|
|
4967
5060
|
|
|
5061
|
+
function composeRequestTag(prefix, tag) {
|
|
5062
|
+
if (prefix === void 0) return tag;
|
|
5063
|
+
const relative = isWorkflowsFamilyPrefix(prefix) ? stripWorkflowRoot(tag) : tag;
|
|
5064
|
+
return `${prefix}.${relative}`;
|
|
5065
|
+
}
|
|
5066
|
+
|
|
5067
|
+
function stripWorkflowRoot(tag) {
|
|
5068
|
+
return tag.startsWith("workflow.") ? tag.slice(9) : tag;
|
|
5069
|
+
}
|
|
5070
|
+
|
|
4968
5071
|
function buildTaggedClient(client, fallback) {
|
|
4969
|
-
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip
|
|
5072
|
+
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip ? stripWorkflowRoot(tag) : tag, stamp = options => options === void 0 ? {
|
|
4970
5073
|
tag: normalize(fallback)
|
|
4971
5074
|
} : options.tag === void 0 ? {
|
|
4972
5075
|
...options,
|
|
@@ -4996,8 +5099,7 @@ function buildTaggedClient(client, fallback) {
|
|
|
4996
5099
|
commit: options => target.commit(stamp(options))
|
|
4997
5100
|
};
|
|
4998
5101
|
return wrapped;
|
|
4999
|
-
}
|
|
5000
|
-
return {
|
|
5102
|
+
}, overrides = {
|
|
5001
5103
|
[RAW_CLIENT]: unwrapRequestTag(client),
|
|
5002
5104
|
fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
|
|
5003
5105
|
getDocument: (id, options) => client.getDocument(id, stamp(options)),
|
|
@@ -5014,6 +5116,14 @@ function buildTaggedClient(client, fallback) {
|
|
|
5014
5116
|
request: opts => client.request(stamp(opts))
|
|
5015
5117
|
} : {}
|
|
5016
5118
|
};
|
|
5119
|
+
return new Proxy(client, {
|
|
5120
|
+
has: (target, property) => Object.hasOwn(overrides, property) || property in target,
|
|
5121
|
+
get: (target, property) => {
|
|
5122
|
+
if (Object.hasOwn(overrides, property)) return Reflect.get(overrides, property, overrides);
|
|
5123
|
+
const value = Reflect.get(target, property, target);
|
|
5124
|
+
return typeof value == "function" ? value.bind(target) : value;
|
|
5125
|
+
}
|
|
5126
|
+
});
|
|
5017
5127
|
}
|
|
5018
5128
|
|
|
5019
5129
|
const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
|
|
@@ -5028,10 +5138,7 @@ function pinApiVersion(client) {
|
|
|
5028
5138
|
}
|
|
5029
5139
|
|
|
5030
5140
|
function taggedResolver(resolver, fallback) {
|
|
5031
|
-
|
|
5032
|
-
const client = resolver(parsed);
|
|
5033
|
-
return client === void 0 ? void 0 : withRequestTag(pinApiVersion(client), fallback);
|
|
5034
|
-
};
|
|
5141
|
+
return mapResourceClientResolver(resolver, client => withRequestTag(pinApiVersion(client), fallback));
|
|
5035
5142
|
}
|
|
5036
5143
|
|
|
5037
5144
|
function taggedScope(args, tag) {
|
|
@@ -5061,16 +5168,20 @@ function guardsForResource(client) {
|
|
|
5061
5168
|
});
|
|
5062
5169
|
}
|
|
5063
5170
|
|
|
5064
|
-
function
|
|
5171
|
+
function instancesGuardQuery(instanceIds) {
|
|
5065
5172
|
return {
|
|
5066
|
-
query: "*[_type == $guardType && sourceInstanceId
|
|
5173
|
+
query: "*[_type == $guardType && sourceInstanceId in $instanceIds] | order(_id asc)",
|
|
5067
5174
|
params: {
|
|
5068
5175
|
guardType: GUARD_DOC_TYPE,
|
|
5069
|
-
|
|
5176
|
+
instanceIds: [ ...instanceIds ]
|
|
5070
5177
|
}
|
|
5071
5178
|
};
|
|
5072
5179
|
}
|
|
5073
5180
|
|
|
5181
|
+
function instanceGuardQuery(instanceId) {
|
|
5182
|
+
return instancesGuardQuery([ instanceId ]);
|
|
5183
|
+
}
|
|
5184
|
+
|
|
5074
5185
|
function verdictGuardsForInstance(client, instanceId) {
|
|
5075
5186
|
const {query: query, params: params} = instanceGuardQuery(instanceId);
|
|
5076
5187
|
return fetchGuards({
|
|
@@ -5172,7 +5283,7 @@ function dedupById(guards) {
|
|
|
5172
5283
|
return [ ...new Map(guards.map(g => [ g._id, g ])).values() ].sort((a, b) => a._id.localeCompare(b._id));
|
|
5173
5284
|
}
|
|
5174
5285
|
|
|
5175
|
-
const GUARD_OWNER = "robot:workflow-engine";
|
|
5286
|
+
const GUARD_OWNER = "robot:workflow-engine", DELETE_CHUNK_SIZE = 200;
|
|
5176
5287
|
|
|
5177
5288
|
function resolveGuardRoute(guard, ctx) {
|
|
5178
5289
|
const targets = resolveIdRefTargets(guard.match.idRefs, ctx);
|
|
@@ -5225,10 +5336,9 @@ function resolveGuard({guard: guard, instance: instance, stageName: stageName, n
|
|
|
5225
5336
|
};
|
|
5226
5337
|
}
|
|
5227
5338
|
|
|
5228
|
-
async function upsertGuard(
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
})) {
|
|
5339
|
+
async function upsertGuard(args) {
|
|
5340
|
+
const {client: client, doc: doc, exists: exists} = args;
|
|
5341
|
+
if (!exists) {
|
|
5232
5342
|
await client.create(doc, {
|
|
5233
5343
|
...SYNC_COMMIT,
|
|
5234
5344
|
tag: REQUEST_TAG.guardDeploy
|
|
@@ -5254,7 +5364,8 @@ function resolvedStageGuards(args) {
|
|
|
5254
5364
|
});
|
|
5255
5365
|
resolved !== null && out.push({
|
|
5256
5366
|
client: args.clientForGdr(resolved.routeGdr),
|
|
5257
|
-
|
|
5367
|
+
resourceKey: invariants.resourceGdr(invariants.resourceFromParsed(resolved.routeGdr)),
|
|
5368
|
+
value: resolved.doc
|
|
5258
5369
|
});
|
|
5259
5370
|
}
|
|
5260
5371
|
return out;
|
|
@@ -5271,12 +5382,54 @@ function resolvedStageGuardRoutes(args) {
|
|
|
5271
5382
|
const route = resolveGuardRoute(guard, ctx);
|
|
5272
5383
|
route !== null && out.push({
|
|
5273
5384
|
client: args.clientForGdr(route.routeGdr),
|
|
5274
|
-
|
|
5385
|
+
resourceKey: invariants.resourceGdr(invariants.resourceFromParsed(route.routeGdr)),
|
|
5386
|
+
value: route.guardId
|
|
5275
5387
|
});
|
|
5276
5388
|
}
|
|
5277
5389
|
return out;
|
|
5278
5390
|
}
|
|
5279
5391
|
|
|
5392
|
+
function groupByResource(routed) {
|
|
5393
|
+
const groups = /* @__PURE__ */ new Map;
|
|
5394
|
+
for (const item of routed) {
|
|
5395
|
+
const existing = groups.get(item.resourceKey);
|
|
5396
|
+
if (existing !== void 0) {
|
|
5397
|
+
existing.values.push(item.value);
|
|
5398
|
+
continue;
|
|
5399
|
+
}
|
|
5400
|
+
groups.set(item.resourceKey, {
|
|
5401
|
+
client: item.client,
|
|
5402
|
+
resourceKey: item.resourceKey,
|
|
5403
|
+
values: [ item.value ]
|
|
5404
|
+
});
|
|
5405
|
+
}
|
|
5406
|
+
return [ ...groups.values() ];
|
|
5407
|
+
}
|
|
5408
|
+
|
|
5409
|
+
async function existingGuardIds(groups) {
|
|
5410
|
+
const entries = await Promise.all(groups.map(async ({client: client, resourceKey: resourceKey, values: values}) => {
|
|
5411
|
+
const ids = values.map(doc => doc._id), existing = await client.fetch("*[_id in $ids]._id", {
|
|
5412
|
+
ids: ids
|
|
5413
|
+
}, {
|
|
5414
|
+
tag: REQUEST_TAG.guardDeploy
|
|
5415
|
+
});
|
|
5416
|
+
return [ resourceKey, new Set(existing) ];
|
|
5417
|
+
}));
|
|
5418
|
+
return new Map(entries);
|
|
5419
|
+
}
|
|
5420
|
+
|
|
5421
|
+
async function observedGuards(groups) {
|
|
5422
|
+
const entries = await Promise.all(groups.map(async ({client: client, resourceKey: resourceKey, values: ids}) => {
|
|
5423
|
+
const guards = await client.fetch("*[_id in $ids]{_id, predicate, _rev}", {
|
|
5424
|
+
ids: ids
|
|
5425
|
+
}, {
|
|
5426
|
+
tag: REQUEST_TAG.guardRetract
|
|
5427
|
+
});
|
|
5428
|
+
return [ resourceKey, new Map(guards.map(guard => [ guard._id, guard ])) ];
|
|
5429
|
+
}));
|
|
5430
|
+
return new Map(entries);
|
|
5431
|
+
}
|
|
5432
|
+
|
|
5280
5433
|
async function committedInstance(args) {
|
|
5281
5434
|
return getInstanceDocument(args.client, args.instance._id);
|
|
5282
5435
|
}
|
|
@@ -5284,10 +5437,15 @@ async function committedInstance(args) {
|
|
|
5284
5437
|
async function deployStageGuards(args) {
|
|
5285
5438
|
const live = await committedInstance(args);
|
|
5286
5439
|
if (live === void 0 || live.currentStage !== args.stageName || live.abortedAt !== void 0) return;
|
|
5440
|
+
const routed = resolvedStageGuards(args), existingByResource = await existingGuardIds(groupByResource(routed));
|
|
5287
5441
|
let deployed = 0;
|
|
5288
|
-
for (const {client: client,
|
|
5442
|
+
for (const {client: client, resourceKey: resourceKey, value: doc} of routed) {
|
|
5289
5443
|
try {
|
|
5290
|
-
await upsertGuard(
|
|
5444
|
+
await upsertGuard({
|
|
5445
|
+
client: client,
|
|
5446
|
+
doc: doc,
|
|
5447
|
+
exists: existingByResource.get(resourceKey)?.has(doc._id) ?? !1
|
|
5448
|
+
});
|
|
5291
5449
|
} catch (cause) {
|
|
5292
5450
|
throw deployed > 0 ? new PartialGuardDeployError({
|
|
5293
5451
|
stageName: args.stageName,
|
|
@@ -5300,13 +5458,11 @@ async function deployStageGuards(args) {
|
|
|
5300
5458
|
}
|
|
5301
5459
|
|
|
5302
5460
|
async function retractStageGuards(args) {
|
|
5303
|
-
const observed = [];
|
|
5304
|
-
for (const {client: client,
|
|
5305
|
-
const guard =
|
|
5306
|
-
tag: REQUEST_TAG.guardRetract
|
|
5307
|
-
});
|
|
5461
|
+
const observed = [], routed = resolvedStageGuardRoutes(args), guardsByResource = await observedGuards(groupByResource(routed));
|
|
5462
|
+
for (const {client: client, resourceKey: resourceKey, value: guardId} of routed) {
|
|
5463
|
+
const guard = guardsByResource.get(resourceKey)?.get(guardId);
|
|
5308
5464
|
if (guard) {
|
|
5309
|
-
if (guard._rev === void 0) throw new Error(`Cannot retract guard ${guardId}: persisted document has no revision`);
|
|
5465
|
+
if (guard._rev === void 0 || guard._rev === null) throw new Error(`Cannot retract guard ${guardId}: persisted document has no revision`);
|
|
5310
5466
|
observed.push({
|
|
5311
5467
|
client: client,
|
|
5312
5468
|
guardId: guardId,
|
|
@@ -5337,10 +5493,11 @@ async function deleteOrphanedDefinitionGuards(args) {
|
|
|
5337
5493
|
let count = 0;
|
|
5338
5494
|
for (const {client: resourceClient, guards: guards} of perClient) {
|
|
5339
5495
|
const own = guards.filter(guard => guard.sourceInstanceId.startsWith(ownPartitionPrefix));
|
|
5340
|
-
if (own.length
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5496
|
+
if (own.length !== 0) for (let start = 0; start < own.length; start += DELETE_CHUNK_SIZE) {
|
|
5497
|
+
const chunk = own.slice(start, start + DELETE_CHUNK_SIZE), tx = resourceClient.transaction();
|
|
5498
|
+
for (const guard of chunk) tx.delete(guard._id);
|
|
5499
|
+
await tx.commit(), count += chunk.length;
|
|
5500
|
+
}
|
|
5344
5501
|
}
|
|
5345
5502
|
return count;
|
|
5346
5503
|
}
|
|
@@ -7773,26 +7930,26 @@ async function subjectResourceGrants(args) {
|
|
|
7773
7930
|
async function evaluateInstance(args) {
|
|
7774
7931
|
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
7775
7932
|
invariants.validateTag(tag);
|
|
7776
|
-
const
|
|
7933
|
+
const [access, instance] = await Promise.all([ resolveAccess(client, {
|
|
7777
7934
|
...args.grantsFromPath !== void 0 ? {
|
|
7778
7935
|
grantsFromPath: args.grantsFromPath
|
|
7779
7936
|
} : {}
|
|
7780
|
-
}),
|
|
7937
|
+
}), reload({
|
|
7781
7938
|
client: client,
|
|
7782
7939
|
instanceId: instanceId,
|
|
7783
7940
|
tag: tag
|
|
7784
|
-
}), definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
7941
|
+
}) ]), {actor: actor, grants: grants} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
7785
7942
|
client: client,
|
|
7786
7943
|
workflowResource: workflowResource,
|
|
7787
7944
|
resourceClients: resourceClients
|
|
7788
|
-
}), snapshot = await hydrateSnapshot({
|
|
7945
|
+
}), [snapshot, guards, resourceGrants] = await Promise.all([ hydrateSnapshot({
|
|
7789
7946
|
client: client,
|
|
7790
7947
|
clientForGdr: clientForGdr,
|
|
7791
7948
|
instance: instance
|
|
7792
|
-
}),
|
|
7949
|
+
}), verdictGuardsForInstance(client, instance._id), subjectResourceGrants({
|
|
7793
7950
|
clientForGdr: clientForGdr,
|
|
7794
7951
|
instance: instance
|
|
7795
|
-
});
|
|
7952
|
+
}) ]);
|
|
7796
7953
|
return evaluateFromSnapshot({
|
|
7797
7954
|
instance: instance,
|
|
7798
7955
|
definition: definition,
|
|
@@ -8322,14 +8479,14 @@ function documentPrefilter(documents, params) {
|
|
|
8322
8479
|
|
|
8323
8480
|
function documentArm(filter, params) {
|
|
8324
8481
|
if (filter.documents === void 0 && filter.document === void 0) return;
|
|
8325
|
-
const documents = [ ...filter.documents ?? [], ...filter.document !== void 0 ? [ filter.document ] : [] ];
|
|
8482
|
+
const documents = [ .../* @__PURE__ */ new Set([ ...filter.documents ?? [], ...filter.document !== void 0 ? [ filter.document ] : [] ]) ].sort();
|
|
8326
8483
|
return documentPrefilter(documents, params);
|
|
8327
8484
|
}
|
|
8328
8485
|
|
|
8329
8486
|
function idsArm(filter, params) {
|
|
8330
8487
|
if (filter.ids !== void 0) {
|
|
8331
8488
|
for (const id of filter.ids) if (invariants.isGdrUri(id)) throw new invariants.ContractViolationError(`instancesQuery: every id must be a bare instance document id (an instance's _id is never resource-qualified); got a GDR URI: ${JSON.stringify(id)}`);
|
|
8332
|
-
return params.ids = [ ...filter.ids ], "_id in $ids";
|
|
8489
|
+
return params.ids = [ ...new Set(filter.ids) ].sort(), "_id in $ids";
|
|
8333
8490
|
}
|
|
8334
8491
|
}
|
|
8335
8492
|
|
|
@@ -10540,7 +10697,7 @@ function isCancelledCompletion(data) {
|
|
|
10540
10697
|
}
|
|
10541
10698
|
|
|
10542
10699
|
async function drainEffectsInternal(args) {
|
|
10543
|
-
const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, effectHandlers: effectHandlers, missingHandler: missingHandler, logger: logger, handlerClient:
|
|
10700
|
+
const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, effectHandlers: effectHandlers, missingHandler: missingHandler, logger: logger, handlerClient: rawHandlerClient, handlerResourceClients: rawHandlerResourceClients} = args, cascadeTelemetry = drainCascadeTelemetry(args.telemetry), {client: client, resourceClients: resourceClients} = taggedScope(args, REQUEST_TAG.drain), leaseMs = args.leaseMs ?? DEFAULT_EFFECT_LEASE_MS, clock = args.clock ?? wallClock, handlerClient = effectHandlerClient(rawHandlerClient), handlerResourceClients = effectHandlerResolver(rawHandlerResourceClients), routeGdr = buildClientForGdr({
|
|
10544
10701
|
client: handlerClient,
|
|
10545
10702
|
workflowResource: workflowResource,
|
|
10546
10703
|
resourceClients: handlerResourceClients
|
|
@@ -10906,22 +11063,30 @@ function createInstanceSession(args) {
|
|
|
10906
11063
|
}, tickScope = opScope(REQUEST_TAG.tick), fireScope = opScope(REQUEST_TAG.fireAction), editScope = opScope(REQUEST_TAG.editField), evalScope = opScope(REQUEST_TAG.evaluate);
|
|
10907
11064
|
let overlay = /* @__PURE__ */ new Map;
|
|
10908
11065
|
const previews = /* @__PURE__ */ new Map;
|
|
10909
|
-
let heldGuards = [], committing = !1, buffered
|
|
10910
|
-
const
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
11066
|
+
let heldGuards = [], committing = !1, buffered;
|
|
11067
|
+
const bufferedDocuments = /* @__PURE__ */ new Map;
|
|
11068
|
+
let deferredUpdateError;
|
|
11069
|
+
const flushDeferredError = () => {
|
|
11070
|
+
if (deferredUpdateError === void 0) return;
|
|
11071
|
+
const failure = deferredUpdateError;
|
|
11072
|
+
throw deferredUpdateError = void 0, failure;
|
|
11073
|
+
}, selfUri = () => invariants.gdrFromResource(instance.workflowResource, instance._id), applyDocument = (ld, target) => {
|
|
11074
|
+
const owned = {
|
|
11075
|
+
doc: structuredClone(ld.doc),
|
|
11076
|
+
resource: ld.resource
|
|
11077
|
+
}, uri = invariants.gdrFromResource(owned.resource, owned.doc._id);
|
|
11078
|
+
if (uri === selfUri()) {
|
|
11079
|
+
const rawStamp = owned.doc._updatedAt;
|
|
11080
|
+
!invariants.isParseableInstant(rawStamp) || owned.doc._type !== invariants.WORKFLOW_INSTANCE_TYPE ? asHeldInstance(owned.doc) : Date.parse(rawStamp) > Date.parse(instance._updatedAt) && (instance = asHeldInstance(owned.doc));
|
|
11081
|
+
return;
|
|
10923
11082
|
}
|
|
11083
|
+
target.set(uri, owned);
|
|
11084
|
+
}, applyUpdate = docs => {
|
|
11085
|
+
const next = /* @__PURE__ */ new Map;
|
|
11086
|
+
for (const ld of docs) applyDocument(ld, next);
|
|
10924
11087
|
overlay = next;
|
|
11088
|
+
}, applyDocumentUpdate = doc => {
|
|
11089
|
+
applyDocument(doc, overlay);
|
|
10925
11090
|
}, access = () => resolveAccess(client, {
|
|
10926
11091
|
...args.grantsFromPath !== void 0 ? {
|
|
10927
11092
|
grantsFromPath: args.grantsFromPath
|
|
@@ -11047,6 +11212,12 @@ function createInstanceSession(args) {
|
|
|
11047
11212
|
deferredUpdateError = err;
|
|
11048
11213
|
}
|
|
11049
11214
|
}
|
|
11215
|
+
for (const next of bufferedDocuments.values()) try {
|
|
11216
|
+
applyDocumentUpdate(next);
|
|
11217
|
+
} catch (err) {
|
|
11218
|
+
deferredUpdateError = err;
|
|
11219
|
+
}
|
|
11220
|
+
bufferedDocuments.clear();
|
|
11050
11221
|
}
|
|
11051
11222
|
};
|
|
11052
11223
|
return {
|
|
@@ -11054,15 +11225,26 @@ function createInstanceSession(args) {
|
|
|
11054
11225
|
return subscriptionDocumentsForInstance(instance);
|
|
11055
11226
|
},
|
|
11056
11227
|
update(docs) {
|
|
11057
|
-
if (committing) buffered = docs; else try {
|
|
11228
|
+
if (committing) buffered = docs, bufferedDocuments.clear(); else try {
|
|
11058
11229
|
applyUpdate(docs);
|
|
11059
11230
|
} catch (err) {
|
|
11060
11231
|
throw deferredUpdateError = void 0, err;
|
|
11061
11232
|
}
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11233
|
+
flushDeferredError();
|
|
11234
|
+
},
|
|
11235
|
+
updateDocument(doc) {
|
|
11236
|
+
if (committing) {
|
|
11237
|
+
const uri = invariants.gdrFromResource(doc.resource, doc.doc._id);
|
|
11238
|
+
bufferedDocuments.set(uri, {
|
|
11239
|
+
doc: structuredClone(doc.doc),
|
|
11240
|
+
resource: doc.resource
|
|
11241
|
+
});
|
|
11242
|
+
} else try {
|
|
11243
|
+
applyDocumentUpdate(doc);
|
|
11244
|
+
} catch (err) {
|
|
11245
|
+
throw deferredUpdateError = void 0, err;
|
|
11065
11246
|
}
|
|
11247
|
+
flushDeferredError();
|
|
11066
11248
|
},
|
|
11067
11249
|
updateGuards(guards) {
|
|
11068
11250
|
heldGuards = guards.map(guard => parseGuardDocument(structuredClone(guard)));
|
|
@@ -12376,10 +12558,14 @@ exports.instanceGuardQuery = instanceGuardQuery;
|
|
|
12376
12558
|
|
|
12377
12559
|
exports.instanceWatchesDocument = instanceWatchesDocument;
|
|
12378
12560
|
|
|
12561
|
+
exports.instancesGuardQuery = instancesGuardQuery;
|
|
12562
|
+
|
|
12379
12563
|
exports.instancesQuery = instancesQuery;
|
|
12380
12564
|
|
|
12381
12565
|
exports.isClaimExpired = isClaimExpired;
|
|
12382
12566
|
|
|
12567
|
+
exports.isClientProjectUser = isClientProjectUser;
|
|
12568
|
+
|
|
12383
12569
|
exports.isDefinitionApplicable = isDefinitionApplicable;
|
|
12384
12570
|
|
|
12385
12571
|
exports.isFilterScopedOut = isFilterScopedOut;
|