Milestone 0: import zappier billing, Verae middleware, and Zapier research

Compose-ready workspace: packages/zappier (rate card, portal, Stripe),
packages/verae-zapier-middleware (timestamp + NATS), packages/verae-zapier
(CLI app), vendor/zapier-platform, and research/zapier vendor corpus.

Gate 0 structure checks pass. Product code and research are not yet wired.
This commit is contained in:
George Lambert 2026-09-09 02:37:36 -04:00
commit b4150c8250
1364 changed files with 6814366 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
const AUTH_JSON_SERVER_URL =
process.env.AUTH_JSON_SERVER_URL ||
'https://auth-json-server.zapier-staging.com';
const HTTPBIN_URL =
process.env.HTTPBIN_URL || 'https://httpbin.zapier-tooling.com';
module.exports = {
AUTH_JSON_SERVER_URL,
HTTPBIN_URL,
};

View file

@ -0,0 +1,35 @@
const { AUTH_JSON_SERVER_URL } = require('../constants');
const testAuthSource = `
const responsePromise = z.request({
url: '${AUTH_JSON_SERVER_URL}/me'
});
return responsePromise.then(response => {
if (response.status !== 200) {
throw new Error('Auth failed');
}
return z.JSON.parse(response.content);
});
`;
module.exports = {
legacy: {
authentication: {
mapping: { 'X-Api-Key': '{{api_key}}' },
placement: 'header',
},
},
authentication: {
type: 'custom',
test: { source: testAuthSource },
fields: [
{
key: 'api_key',
label: 'API Key',
type: 'string',
required: true,
},
],
},
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
const { AUTH_JSON_SERVER_URL } = require('../constants');
const testAuthSource = `
const responsePromise = z.request({
url: '${AUTH_JSON_SERVER_URL}/me'
});
return responsePromise.then(response => {
if (response.status !== 200) {
throw new Error('Auth failed');
}
return z.JSON.parse(response.content);
});
`;
const getAuthorizeUrlSource = `
return z.legacyScripting.run(bundle, 'auth.oauth2.authorize');
`;
const getAccessTokenSource = `
return z.legacyScripting.run(bundle, 'auth.oauth2.token');
`;
const refreshAccessTokenSource = `
return z.legacyScripting.run(bundle, 'auth.oauth2.refresh');
`;
module.exports = {
legacy: {
authentication: {
placement: 'header',
mapping: {},
},
},
authentication: {
type: 'oauth2',
test: { source: testAuthSource },
fields: [
// No need to define access_token and refresh_token here, they will be
// added automatically by the backend
{
key: 'something_custom',
type: 'string',
required: true,
computed: true,
},
],
oauth2Config: {
authorizeUrl: {
source: getAuthorizeUrlSource,
},
getAccessToken: {
source: getAccessTokenSource,
},
refreshAccessToken: {
source: refreshAccessTokenSource,
},
autoRefresh: true,
},
},
};

View file

@ -0,0 +1,47 @@
'use strict';
const testAuthSource = `
return z.legacyScripting.run(bundle, 'trigger', 'contact_full');
`;
const getSessionKeySource = `
return z.legacyScripting.run(bundle, 'auth.session');
`;
const getConnectionLabelSource = `
return z.legacyScripting.run(bundle, 'auth.connectionLabel');
`;
module.exports = {
legacy: {
authentication: {
mapping: {
'X-Api-Key': '{{key1}}{{key2}}',
},
placement: 'header',
},
testTrigger: 'contact_full',
},
authentication: {
type: 'session',
test: { source: testAuthSource },
fields: [
{
key: 'username',
label: 'Username',
type: 'string',
required: true,
},
{
key: 'password',
label: 'Password',
type: 'password',
required: true,
},
],
sessionConfig: {
perform: { source: getSessionKeySource },
},
connectionLabel: { source: getConnectionLabelSource },
},
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
require('should');
describe('Utils/Libraries', () => {
it('btoa', (done) => {
const btoa = require('../btoa');
const result = btoa('something');
result.should.equal('c29tZXRoaW5n');
done();
});
it('atob', (done) => {
const atob = require('../atob');
const result = atob('c29tZXRoaW5n');
result.should.equal('something');
done();
});
describe('$', () => {
const $ = require('../$');
it('$.param()', (done) => {
const result = $.param({ test: 'something', more: true, also: '@' });
result.should.equal('test=something&more=true&also=%40');
done();
});
it('$.parseXML()', (done) => {
const xml = $.parseXML('<do><something>also</something></do>');
const result = xml.getElementsByTagName('do').length;
result.should.equal(1);
done();
});
});
});

View file

@ -0,0 +1,88 @@
const should = require('should');
const scriptingRunner = require('../index');
describe('scriptingRunner', () => {
const defaultBundle = {
_legacyUrl: 'https://zapier.com',
inputData: {
user: 'Zapier',
},
authData: {
apiKey: 'Zapier-API-Key',
},
meta: {
frontend: false,
prefill: false,
},
};
const z = {
request: () => {},
};
it('should return nothing if there is no scripting', (done) => {
const event = {
name: 'trigger.poll',
key: 'trigger',
response: {
status: 200,
content: '[{"id": 1, "name": "Zapier"}]',
},
};
const bundle = defaultBundle;
const Zap = {};
const legacyScriptingRunner = scriptingRunner(Zap);
legacyScriptingRunner
.runEvent(event, z, bundle)
.then((result) => {
should(result).eql(undefined);
done();
})
.catch(done);
});
it('should return nothing if there is no event', (done) => {
const event = {};
const bundle = defaultBundle;
const Zap = {
trigger_poll: () => true,
};
const legacyScriptingRunner = scriptingRunner(Zap);
legacyScriptingRunner
.runEvent(event, z, bundle)
.then((result) => {
should(result).eql(undefined);
done();
})
.catch(done);
});
it('should return nothing if there is no event.name', (done) => {
const event = {
key: 'trigger',
response: {
status: 200,
content: '[{"id": 1, "name": "Zapier"}]',
},
};
const bundle = defaultBundle;
const Zap = {
trigger_poll: () => true,
};
const legacyScriptingRunner = scriptingRunner(Zap);
legacyScriptingRunner
.runEvent(event, z, bundle)
.then((result) => {
should(result).eql(undefined);
done();
})
.catch(done);
});
});

View file

@ -0,0 +1,59 @@
const { renderTemplate } = require('../middleware-factory');
describe('middleware renderTemplate security', () => {
it('should handle normal template rendering', () => {
const context = { clientId: 'test123', secret: 'mysecret' };
const template = 'Client: {{clientId}}, Secret: {{secret}}';
const result = renderTemplate(template, context);
result.should.equal('Client: test123, Secret: mysecret');
});
it('should prevent code injection in middleware templates', () => {
const context = {
clientId: 'test123',
malicious: 'process.exit(1)',
};
// This should NOT execute the malicious code
const result = renderTemplate(
'ID: {{clientId}}, Value: {{malicious}}',
context,
);
result.should.equal('ID: test123, Value: process.exit(1)');
});
it('should handle non-string template input safely in middleware', () => {
const context = { test: 'value' };
(() => {
renderTemplate({}, context);
}).should.throw('Template string must be a primitive');
(() => {
renderTemplate([], context);
}).should.throw('Template string must be a primitive');
(() => {
renderTemplate(() => {
console.log('do evil stuff');
}, context);
}).should.throw('Template string must be a primitive');
});
it('should handle template errors gracefully in middleware', () => {
const context = { name: 'John' };
// Malformed template should return original string, not crash
const result = renderTemplate('{{unclosed', context);
result.should.equal('{{unclosed');
});
it('should handle undefined variables with defaults', () => {
const context = { name: 'John' };
// renderTemplate sets undefined vars to empty string
const result = renderTemplate('{{name}} {{undefined_var}}', context);
result.should.equal('John ');
});
});

View file

@ -0,0 +1,122 @@
const should = require('should');
const z = require('../zfactory')();
const { HTTPBIN_URL } = require('./constants');
describe('z', () => {
it('z.hash', (done) => {
const result = z.hash('sha256', 'my awesome string');
result.should.equal(
'97f13a1635524dd41daca6601e5d9fe07e10e62790851e527b039851b1f8b9a1',
);
done();
});
it('z.hmac', (done) => {
const result = z.hmac('sha1', 'secret', 'signme');
result.should.equal('f67a0be1fa49a3f1dbd659726d8983b838ee6e7d');
done();
});
it('z.snipify', (done) => {
const result = z.snipify('something');
result.should.equal(':censored:9:720a531ca0:');
done();
});
it('z.request - sync', () => {
const bundleRequest = {
method: 'GET',
url: `${HTTPBIN_URL}/get`,
params: {
hello: 'world',
},
headers: {
Accept: 'application/json',
},
auth: null,
data: null,
};
const response = z.request(bundleRequest);
response.should.have.property('status_code');
response.should.have.property('headers');
response.should.have.property('content');
response.status_code.should.eql(200);
const results = JSON.parse(response.content);
results.args.should.deepEqual({ hello: ['world'] });
results.headers.Accept.should.deepEqual(['application/json']);
});
it('z.request - async', (done) => {
const bundleRequest = {
method: 'POST',
url: `${HTTPBIN_URL}/post`,
params: {
hello: 'world',
},
headers: {
Accept: 'application/json',
},
auth: null,
data: JSON.stringify({
world: 'hello',
}),
};
z.request(bundleRequest, (error, response) => {
should(error).eql(null);
response.should.have.property('status_code');
response.should.have.property('headers');
response.should.have.property('content');
response.status_code.should.eql(200);
const results = JSON.parse(response.content);
results.args.should.eql({ hello: ['world'] });
// Current version of httpbin.zapier-tooling.com encodes the input in
// base64 and returns it, so we need to decode it here.
const [header, encodedBody] = results.data.split(',');
header.should.eql('data:application/octet-stream;base64');
const decodedBody = Buffer.from(encodedBody, 'base64').toString('utf8');
decodedBody.should.eql(bundleRequest.data);
results.headers.Accept.should.deepEqual(['application/json']);
done();
});
});
it('z.JSON.parse', (done) => {
const result = z.JSON.parse('{"hello": "world"}');
result.should.have.property('hello');
result.hello.should.eql('world');
const invalidJsonString = '{invalid"hello": "world"}';
try {
z.JSON.parse(invalidJsonString);
} catch (e) {
e.name.should.eql('Error');
e.message.should.eql(
`Error parsing response. We got: "${invalidJsonString}"`,
);
done();
}
});
it('z.JSON.stringify', (done) => {
const result = z.JSON.stringify({
hello: 'world',
});
result.should.equal('{"hello":"world"}');
done();
});
it('z.AWS', (done) => {
const AWS = z.AWS();
AWS.config.getCredentials(done);
});
});