feat(platform): add managed data product history plane
This commit is contained in:
@@ -72,7 +72,7 @@ export function normalizeWriterBindingRequest(value, { now = new Date(), maxTtlD
|
||||
* generated and stored inside Engine; EDP receives only its SHA-256 digest.
|
||||
* `generation` makes a retry address the same immutable binding generation.
|
||||
*/
|
||||
export function normalizeManagedWriterBindingRequest(value, { now = new Date(), maxTtlDays = 90 } = {}) {
|
||||
export function normalizeManagedWriterBindingRequest(value) {
|
||||
if (!isPlainObject(value) || !isPlainObject(value.source)) {
|
||||
throw writerBindingError("managed_writer_binding_request_invalid");
|
||||
}
|
||||
@@ -83,11 +83,16 @@ export function normalizeManagedWriterBindingRequest(value, { now = new Date(),
|
||||
throw writerBindingError("managed_writer_binding_request_fields_invalid");
|
||||
}
|
||||
|
||||
const scope = normalizeWriterBindingRequest({
|
||||
source: value.source,
|
||||
allowedDataProductIds: value.allowedDataProductIds,
|
||||
expiresAt: value.expiresAt,
|
||||
}, { now, maxTtlDays });
|
||||
const tenantId = normalizeIdentifier(value.source.tenantId);
|
||||
const connectionId = normalizeIdentifier(value.source.connectionId);
|
||||
const providerId = normalizeIdentifier(value.source.providerId);
|
||||
const allowedDataProductIds = uniqueIdentifiers(value.allowedDataProductIds);
|
||||
if (!tenantId || !connectionId || !providerId || !allowedDataProductIds.length) {
|
||||
throw writerBindingError("managed_writer_binding_scope_invalid");
|
||||
}
|
||||
if (value.expiresAt !== null) {
|
||||
throw writerBindingError("managed_writer_binding_must_be_durable");
|
||||
}
|
||||
const generation = Number(value.generation);
|
||||
if (!Number.isSafeInteger(generation) || generation < 1 || generation > 2_147_483_647) {
|
||||
throw writerBindingError("managed_writer_binding_generation_invalid");
|
||||
@@ -98,8 +103,11 @@ export function normalizeManagedWriterBindingRequest(value, { now = new Date(),
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
...scope,
|
||||
allowedDataProductIds: Object.freeze([...scope.allowedDataProductIds].sort()),
|
||||
tenantId,
|
||||
connectionId,
|
||||
providerId,
|
||||
allowedDataProductIds: Object.freeze([...allowedDataProductIds].sort()),
|
||||
expiresAt: null,
|
||||
generation,
|
||||
capabilityDigest,
|
||||
});
|
||||
@@ -111,13 +119,26 @@ export function writerBindingRequestHash(policy) {
|
||||
connectionId: policy.connectionId,
|
||||
providerId: policy.providerId,
|
||||
allowedDataProductIds: [...policy.allowedDataProductIds].sort(),
|
||||
expiresAt: new Date(policy.expiresAt).toISOString(),
|
||||
expiresAt: null,
|
||||
generation: policy.generation,
|
||||
capabilityDigest: policy.capabilityDigest,
|
||||
});
|
||||
return createHash("sha256").update(canonical, "utf8").digest("hex");
|
||||
}
|
||||
|
||||
export function canMigrateManagedWriterBindingToDurable(binding, policy, now = new Date()) {
|
||||
if (!isPlainObject(binding) || !isPlainObject(policy) || binding.active !== true) return false;
|
||||
const expiresAt = new Date(binding.expiresAt);
|
||||
if (binding.expiresAt === null || Number.isNaN(expiresAt.getTime()) || expiresAt <= now) return false;
|
||||
return binding.tenantId === policy.tenantId
|
||||
&& binding.connectionId === policy.connectionId
|
||||
&& binding.providerId === policy.providerId
|
||||
&& binding.capabilityDigest === policy.capabilityDigest
|
||||
&& JSON.stringify(uniqueIdentifiers(binding.allowedDataProductIds).sort())
|
||||
=== JSON.stringify(uniqueIdentifiers(policy.allowedDataProductIds).sort())
|
||||
&& policy.expiresAt === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a caller-provided, deliberately unscoped intake envelope into the
|
||||
* canonical scoped form. Caller scope is rejected, never trusted or merged.
|
||||
@@ -202,7 +223,7 @@ export function safeWriterBinding(binding) {
|
||||
providerId: binding.providerId,
|
||||
allowedDataProductIds: uniqueIdentifiers(binding.allowedDataProductIds),
|
||||
active: binding.active === true,
|
||||
expiresAt: new Date(binding.expiresAt).toISOString(),
|
||||
expiresAt: binding.expiresAt === null ? null : new Date(binding.expiresAt).toISOString(),
|
||||
createdAt: binding.createdAt ? new Date(binding.createdAt).toISOString() : undefined,
|
||||
rotatedAt: binding.rotatedAt ? new Date(binding.rotatedAt).toISOString() : undefined,
|
||||
revokedAt: binding.revokedAt ? new Date(binding.revokedAt).toISOString() : undefined,
|
||||
@@ -214,6 +235,7 @@ export function writerBindingError(code) {
|
||||
}
|
||||
|
||||
function bindingIsCurrent(binding, now) {
|
||||
if (binding.expiresAt === null) return true;
|
||||
const expiresAt = new Date(binding.expiresAt);
|
||||
return !Number.isNaN(expiresAt.getTime()) && expiresAt > now;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user