Initial import of verae-middleware from zapier monorepo
This commit is contained in:
commit
c6f7d93bbb
66 changed files with 6590 additions and 0 deletions
169
src/services/timestampService.js
Normal file
169
src/services/timestampService.js
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* @fileoverview Timestamp create/status operations with billing + job enqueue.
|
||||
* @module services/timestampService
|
||||
*/
|
||||
|
||||
import { config } from '../config.js';
|
||||
import { veraeClient } from '../clients/veraeClient.js';
|
||||
import { enqueueJob } from '../store/jobWatchers.js';
|
||||
import { checkEntitlement, recordUsage } from './entitlementService.js';
|
||||
import { createDebugger } from '../debug/logger.js';
|
||||
import { getTraceId } from '../debug/trace-context.js';
|
||||
|
||||
const log = createDebugger('jobs');
|
||||
|
||||
/**
|
||||
* Enqueue async job watch via NATS or in-process store.
|
||||
* @param {object} ctx
|
||||
* @param {string} jobId
|
||||
*/
|
||||
async function enqueueWatchForJob(ctx, jobId) {
|
||||
const traceId = getTraceId() ?? undefined;
|
||||
|
||||
if (config.natsEnabled) {
|
||||
const { enqueueWatch } = await import('../nats/publishers.js');
|
||||
await enqueueWatch({
|
||||
tenantId: ctx.tenantId,
|
||||
jobId,
|
||||
// Prefer re-login in worker; include token for MVP simplicity when mock
|
||||
veraeToken: ctx.veraeToken,
|
||||
maxAttempts: config.jobPollMaxAttempts,
|
||||
intervalMs: config.jobPollIntervalMs,
|
||||
traceId,
|
||||
});
|
||||
log.debug('watch enqueued on NATS', { jobId, tenantId: ctx.tenantId });
|
||||
return;
|
||||
}
|
||||
|
||||
enqueueJob({
|
||||
tenantId: ctx.tenantId,
|
||||
jobId,
|
||||
veraeToken: ctx.veraeToken,
|
||||
traceId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx - Auth context with tenantId, veraeToken
|
||||
* @param {{ data?: string, hashAlg?: string, sha256?: string, publicMetadata?: object, privateMetadata?: object }} body
|
||||
* @returns {Promise<{ jobId: string, sha256?: string, existing?: boolean }>}
|
||||
*/
|
||||
export async function createTimestamp(ctx, body) {
|
||||
checkEntitlement(ctx.tenantId, 'timestamp');
|
||||
const result = await veraeClient.createTimestamp(ctx.veraeToken, body);
|
||||
recordUsage(ctx.tenantId, 'timestamp');
|
||||
|
||||
await enqueueWatchForJob(ctx, result.jobId);
|
||||
|
||||
log.debug('timestamp created', { jobId: result.jobId, tenantId: ctx.tenantId });
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {{ data: string, hashAlg?: string }} body
|
||||
* @returns {Promise<object>} StatusResponse
|
||||
*/
|
||||
export async function createTimestampAndWait(ctx, body) {
|
||||
const created = await createTimestamp(ctx, body);
|
||||
|
||||
if (config.natsEnabled) {
|
||||
const { waitForJobEvent } = await import('../nats/wait.js');
|
||||
const event = await waitForJobEvent(created.jobId, config.waitTimeoutMs);
|
||||
if (event?.status) {
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
log.debug('wait via NATS event', {
|
||||
jobId: created.jobId,
|
||||
event: event.event,
|
||||
traceId: event.traceId,
|
||||
});
|
||||
return event.status;
|
||||
}
|
||||
const status = await veraeClient.getStatus(ctx.veraeToken, created.jobId);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
if (status.status === 'pending') {
|
||||
return { id: created.jobId, jobId: created.jobId, status: 'pending' };
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
try {
|
||||
const status = await veraeClient.waitForJob(ctx.veraeToken, created.jobId, {
|
||||
maxAttempts: config.jobPollMaxAttempts,
|
||||
intervalMs: config.jobPollIntervalMs,
|
||||
});
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return status;
|
||||
} catch {
|
||||
const status = await veraeClient.getStatus(ctx.veraeToken, created.jobId);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return { id: created.jobId, jobId: created.jobId, status: status.status ?? 'pending' };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {{ items: Array<{ data: string, hashAlg?: string }> }} body
|
||||
*/
|
||||
export async function createBatchTimestamp(ctx, body) {
|
||||
const itemCount = body.items?.length ?? 0;
|
||||
checkEntitlement(ctx.tenantId, 'batch_timestamp', { amount: itemCount });
|
||||
const result = await veraeClient.createBatchTimestamp(ctx.veraeToken, body);
|
||||
recordUsage(ctx.tenantId, 'batch_timestamp', { amount: itemCount });
|
||||
|
||||
for (const jobId of result.jobIds ?? []) {
|
||||
await enqueueWatchForJob(ctx, jobId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {string} jobId
|
||||
*/
|
||||
export async function getJobStatus(ctx, jobId) {
|
||||
const status = await veraeClient.getStatus(ctx.veraeToken, jobId);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {{ jobIds: string[] }} body
|
||||
*/
|
||||
export async function getBatchJobStatus(ctx, body) {
|
||||
const status = await veraeClient.getBatchStatus(ctx.veraeToken, body);
|
||||
recordUsage(ctx.tenantId, 'status', { amount: body.jobIds?.length ?? 1 });
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {string} jobId
|
||||
*/
|
||||
export async function getJobVerification(ctx, jobId) {
|
||||
const status = await veraeClient.getJobVerification(ctx.veraeToken, jobId);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {string} sha256
|
||||
* @param {{ includeAttached?: boolean, includeTree?: boolean }} [opts]
|
||||
*/
|
||||
export async function lookupHash(ctx, sha256, opts = {}) {
|
||||
const result = await veraeClient.lookupHash(ctx.veraeToken, sha256);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
if (!opts.includeAttached && !opts.includeTree) return result;
|
||||
return {
|
||||
...result,
|
||||
includeAttached: Boolean(opts.includeAttached),
|
||||
includeTree: Boolean(opts.includeTree),
|
||||
note:
|
||||
opts.includeTree && !result?.exists
|
||||
? 'Chain miss: middleware should broadcast verae.archive.query kinds=["tree"] (wired in simulator; live aggregator hook TBD).'
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue