Zapier cloud runs this app against verae-middleware over HTTPS with a
customer zmw_ key; the middleware owns keys, plans, job watching, webhooks,
and the api.veraetime.net client. This commit makes the app cover the whole
middleware surface and match its documented behaviour.
New operations
- creates: batch_verify (POST /verify/batch), batch_status
(POST /status/batch), get_receipt (GET /receipts/{jobId}, optional PDF via
z.stashFile)
- searches: job_verification (GET /status/{jobId}/verification), usage
(GET /auth/me -> plan and month-to-date usage vs limits)
- triggers: timestamp_failed REST Hook alongside timestamp_completed
Behaviour changes
- Create Timestamp / Create Timestamp and Wait accept Data or a 64-hex
SHA256, plus optional public/private metadata dicts, per the user guide.
- Searches return [] on 404 instead of failing the Zap; other errors carry
the middleware message.
- Hook items get id = jobId so Zapier can dedupe; subscribeData is
{ id, event }; performUnsubscribe accepts the legacy bare id.
- The API key is sent as Authorization: Bearer and as x-api-key so the app
works through the middleware today and the access planes / billing edge
that forward only x-api-key.
- afterResponse maps every middleware error body; QUOTA_EXCEEDED,
PLAN_UPGRADE_REQUIRED and BATCH_LIMIT_EXCEEDED include the upgrade URL;
429 becomes a ThrottledError.
- MIDDLEWARE_PATH_PREFIX (default /zapier/v1) for a fronting edge.
Shared code
- lib/middleware.js: base URL, error parsing, 404-as-no-match search
helper, timestamp input/body builder, shared samples and output fields.
- lib/hookTrigger.js: REST Hook factory.
Repo health
- Remove creates/add_numbers.js, which required a file from the sibling
verae-activate package and prevented the app from loading.
- Fix the npm test glob for Node 22; add .gitignore and package-lock.json.
- Version 1.1.0.
Tests and docs
- test/app.test.js rewritten: 25 unit tests with a fake z, no network.
- test/e2e.test.js: opt-in run through zapier-platform-core against a live
middleware (MIDDLEWARE_BASE_URL + MIDDLEWARE_API_KEY); plan-aware and
E2E_SKIP_HOOK_DELIVERY for the lab. Passes on pro and free tenants.
- README: module table, live-lab origins and which are usable, env, and an
"open items" status section; SUMMARY and NATS updated.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
100 lines
3.5 KiB
JavaScript
100 lines
3.5 KiB
JavaScript
/**
|
|
* Verae Zapier Platform app definition.
|
|
*
|
|
* Every operation calls the Verae middleware (`MIDDLEWARE_BASE_URL`,
|
|
* `/zapier/v1/*`). The middleware talks to api.veraetime.net; this app never does.
|
|
* @module index
|
|
*/
|
|
|
|
const authentication = require('./authentication');
|
|
const { describeError } = require('./lib/middleware');
|
|
|
|
const timestampAndWait = require('./creates/timestamp_and_wait');
|
|
const createTimestamp = require('./creates/create_timestamp');
|
|
const batchTimestamp = require('./creates/batch_timestamp');
|
|
const verifyTimestamp = require('./creates/verify_timestamp');
|
|
const batchVerify = require('./creates/batch_verify');
|
|
const batchStatus = require('./creates/batch_status');
|
|
const getReceipt = require('./creates/get_receipt');
|
|
|
|
const jobStatus = require('./searches/job_status');
|
|
const jobVerification = require('./searches/job_verification');
|
|
const hashLookup = require('./searches/hash_lookup');
|
|
const treeLookup = require('./searches/tree_lookup');
|
|
const findUsage = require('./searches/usage');
|
|
|
|
const timestampCompleted = require('./triggers/timestamp_completed');
|
|
const timestampFailed = require('./triggers/timestamp_failed');
|
|
|
|
/**
|
|
* Attach the API key to every outbound request, both ways the stack accepts
|
|
* it: the middleware reads `Authorization: Bearer` or `x-api-key`; the
|
|
* access planes and the zappier billing edge forward only `x-api-key`.
|
|
* @param {object} request
|
|
* @param {object} _z
|
|
* @param {object} bundle
|
|
*/
|
|
const addApiKey = (request, _z, bundle) => {
|
|
request.headers = request.headers || {};
|
|
const key = bundle && bundle.authData && bundle.authData.api_key;
|
|
if (key) {
|
|
if (!request.headers.Authorization) request.headers.Authorization = `Bearer ${key}`;
|
|
if (!request.headers['x-api-key']) request.headers['x-api-key'] = key;
|
|
}
|
|
return request;
|
|
};
|
|
|
|
/**
|
|
* Map middleware errors (`{ error, code, details }`) to Zapier errors.
|
|
* Billing errors carry the upgrade URL; 429 becomes a ThrottledError so
|
|
* Zapier retries later. Requests made with `skipThrowForStatus` are left alone.
|
|
* @param {object} response
|
|
* @param {object} z
|
|
*/
|
|
const mapMiddlewareErrors = (response, z) => {
|
|
if (response.skipThrowForStatus || response.status < 400) {
|
|
return response;
|
|
}
|
|
|
|
const { message, code, upgradeUrl } = describeError(response);
|
|
|
|
if (response.status === 429) {
|
|
throw new z.errors.ThrottledError(message);
|
|
}
|
|
|
|
const billingCodes = new Set(['QUOTA_EXCEEDED', 'PLAN_UPGRADE_REQUIRED', 'BATCH_LIMIT_EXCEEDED']);
|
|
if (response.status === 402 || billingCodes.has(code)) {
|
|
const where = upgradeUrl || 'your billing portal';
|
|
throw new z.errors.Error(`${message}. Upgrade at ${where}.`, code, response.status);
|
|
}
|
|
|
|
throw new z.errors.Error(message, code, response.status);
|
|
};
|
|
|
|
module.exports = {
|
|
version: require('./package.json').version,
|
|
platformVersion: require('zapier-platform-core').version,
|
|
authentication,
|
|
beforeRequest: [addApiKey],
|
|
afterResponse: [mapMiddlewareErrors],
|
|
triggers: {
|
|
[timestampCompleted.key]: timestampCompleted,
|
|
[timestampFailed.key]: timestampFailed,
|
|
},
|
|
creates: {
|
|
[timestampAndWait.key]: timestampAndWait,
|
|
[createTimestamp.key]: createTimestamp,
|
|
[batchTimestamp.key]: batchTimestamp,
|
|
[verifyTimestamp.key]: verifyTimestamp,
|
|
[batchVerify.key]: batchVerify,
|
|
[batchStatus.key]: batchStatus,
|
|
[getReceipt.key]: getReceipt,
|
|
},
|
|
searches: {
|
|
[jobStatus.key]: jobStatus,
|
|
[jobVerification.key]: jobVerification,
|
|
[hashLookup.key]: hashLookup,
|
|
[treeLookup.key]: treeLookup,
|
|
[findUsage.key]: findUsage,
|
|
},
|
|
};
|