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:
commit
b4150c8250
1364 changed files with 6814366 additions and 0 deletions
62
vendor/zapier-platform/example-apps/files/.gitignore
vendored
Normal file
62
vendor/zapier-platform/example-apps/files/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# environment variables file
|
||||
.env
|
||||
.environment
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
30
vendor/zapier-platform/example-apps/files/README.md
vendored
Normal file
30
vendor/zapier-platform/example-apps/files/README.md
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# files
|
||||
|
||||
This Zapier integration project is generated by the `zapier-platform init` CLI command.
|
||||
|
||||
These are what you normally do next:
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install # or you can use yarn
|
||||
|
||||
# Run tests
|
||||
zapier-platform test
|
||||
|
||||
# Register the integration on Zapier if you haven't
|
||||
zapier-platform register "App Title"
|
||||
|
||||
# Or you can link to an existing integration on Zapier
|
||||
zapier-platform link
|
||||
|
||||
# Push it to Zapier
|
||||
zapier-platform push
|
||||
```
|
||||
|
||||
Find out more on the latest docs: https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md.
|
||||
|
||||
# The "files" Template
|
||||
|
||||
This example has a trigger and a create showcasing file handling.
|
||||
|
||||
Find out more in the docs: https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md#stashing-files.
|
||||
64
vendor/zapier-platform/example-apps/files/creates/uploadFile_v10.js
vendored
Normal file
64
vendor/zapier-platform/example-apps/files/creates/uploadFile_v10.js
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
const http = require('https'); // require('http') if your URL is not https
|
||||
|
||||
const FormData = require('form-data');
|
||||
|
||||
// Getting a stream directly from http. This only works on core 10+. For core
|
||||
// 9.x compatible code, see uploadFile_v9.js.
|
||||
const makeDownloadStream = (url) =>
|
||||
new Promise((resolve, reject) => {
|
||||
http
|
||||
.request(url, (res) => {
|
||||
// We can risk missing the first n bytes if we don't pause!
|
||||
res.pause();
|
||||
resolve(res);
|
||||
})
|
||||
.on('error', reject)
|
||||
.end();
|
||||
});
|
||||
|
||||
const perform = async (z, bundle) => {
|
||||
// bundle.inputData.file will in fact be an URL where the file data can be
|
||||
// downloaded from which we do via a stream
|
||||
const stream = await makeDownloadStream(bundle.inputData.file, z);
|
||||
|
||||
const form = new FormData();
|
||||
form.append('filename', bundle.inputData.filename);
|
||||
form.append('file', stream);
|
||||
|
||||
// All set! Resume the stream
|
||||
stream.resume();
|
||||
|
||||
const response = await z.request({
|
||||
url: 'https://auth-json-server.zapier-staging.com/upload',
|
||||
method: 'POST',
|
||||
body: form,
|
||||
headers: {
|
||||
// DO NOT do auth like this! We do this here because this is a file
|
||||
// uploading example so the auth is not the point.
|
||||
'x-api-key': 'secret',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
key: 'uploadFile_v10',
|
||||
noun: 'File',
|
||||
display: {
|
||||
label: 'Upload File v10',
|
||||
description: 'Uploads a file. Only works on zapier-platform-core v10+.',
|
||||
},
|
||||
operation: {
|
||||
inputFields: [
|
||||
{ key: 'filename', required: true, type: 'string', label: 'Filename' },
|
||||
{ key: 'file', required: true, type: 'file', label: 'File' },
|
||||
],
|
||||
perform,
|
||||
sample: {
|
||||
id: 1,
|
||||
filename: 'example.pdf',
|
||||
file: 'SAMPLE FILE',
|
||||
},
|
||||
},
|
||||
};
|
||||
80
vendor/zapier-platform/example-apps/files/creates/uploadFile_v9.js
vendored
Normal file
80
vendor/zapier-platform/example-apps/files/creates/uploadFile_v9.js
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
const { randomBytes } = require('crypto');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const fetch = require('node-fetch');
|
||||
const FormData = require('form-data');
|
||||
|
||||
// Download the HTTP URL to a local temporary file, and make a readable stream
|
||||
// from it. This should work compatibly for all core versions. But if you're
|
||||
// using core v10+, we recommend to use the implementation of uploadFile_v10.js.
|
||||
const makeDownloadStream = async (url) => {
|
||||
// Create a temp file to store the downloaded file
|
||||
const filename = randomBytes(16).toString('hex');
|
||||
const tmpFilePath = path.join(os.tmpdir(), filename);
|
||||
const dest = fs.createWriteStream(tmpFilePath);
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
// Download the file to the temp file. When finished, open a readable stream
|
||||
// from that temp file.
|
||||
return new Promise((resolve, reject) => {
|
||||
response.body
|
||||
.pipe(dest)
|
||||
.on('close', () => {
|
||||
const stream = fs.createReadStream(tmpFilePath).on('close', () => {
|
||||
// Delete the file once the stream is read
|
||||
fs.unlinkSync(tmpFilePath);
|
||||
});
|
||||
resolve(stream);
|
||||
})
|
||||
.on('error', reject);
|
||||
});
|
||||
};
|
||||
|
||||
const perform = async (z, bundle) => {
|
||||
const form = new FormData();
|
||||
|
||||
form.append('filename', bundle.inputData.filename);
|
||||
|
||||
// bundle.inputData.file will in fact be an URL where the file data can be
|
||||
// downloaded from which we do via a stream
|
||||
const stream = await makeDownloadStream(bundle.inputData.file, z);
|
||||
form.append('file', stream);
|
||||
|
||||
const response = await z.request({
|
||||
url: 'https://auth-json-server.zapier-staging.com/upload',
|
||||
method: 'POST',
|
||||
body: form,
|
||||
headers: {
|
||||
// DO NOT do auth like this! We do this here because this is a file
|
||||
// uploading example so the auth is not the point.
|
||||
'x-api-key': 'secret',
|
||||
},
|
||||
});
|
||||
|
||||
return response.json;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
key: 'uploadFile_v9',
|
||||
noun: 'File',
|
||||
display: {
|
||||
label: 'Upload File v9',
|
||||
description:
|
||||
'Uploads a file. Compatible with all versions of zapier-platform-core.',
|
||||
},
|
||||
operation: {
|
||||
inputFields: [
|
||||
{ key: 'filename', required: true, type: 'string', label: 'Filename' },
|
||||
{ key: 'file', required: true, type: 'file', label: 'File' },
|
||||
],
|
||||
perform,
|
||||
sample: {
|
||||
id: 1,
|
||||
filename: 'example.pdf',
|
||||
file: 'SAMPLE FILE',
|
||||
},
|
||||
},
|
||||
};
|
||||
16
vendor/zapier-platform/example-apps/files/hydrators.js
vendored
Normal file
16
vendor/zapier-platform/example-apps/files/hydrators.js
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module.exports = {
|
||||
downloadFile: async (z, bundle) => {
|
||||
// Use standard auth to request the file
|
||||
const filePromise = z.request({
|
||||
url: bundle.inputData.url,
|
||||
raw: true,
|
||||
});
|
||||
|
||||
// When `raw` is true, the result of z.request() can be passed to
|
||||
// z.stashFile(). z.stashFile() will upload the file to a Zapier-owned S3
|
||||
// bucket and return a promise of an S3 URL that allows Zapier to get the
|
||||
// file without auth. If your file URL is permanently publicly available,
|
||||
// you may skip z.stashFile() and return that URL directly here.
|
||||
return z.stashFile(filePromise);
|
||||
},
|
||||
};
|
||||
25
vendor/zapier-platform/example-apps/files/index.js
vendored
Normal file
25
vendor/zapier-platform/example-apps/files/index.js
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
const hydrators = require('./hydrators');
|
||||
const newFile = require('./triggers/newFile');
|
||||
const uploadFileV10 = require('./creates/uploadFile_v10');
|
||||
const uploadFileV9 = require('./creates/uploadFile_v9');
|
||||
|
||||
module.exports = {
|
||||
// This is just shorthand to reference the installed dependencies you have.
|
||||
// Zapier will need to know these before we can upload.
|
||||
version: require('./package.json').version,
|
||||
platformVersion: require('zapier-platform-core').version,
|
||||
|
||||
// Any hydrators go here
|
||||
hydrators,
|
||||
|
||||
// If you want your triggers to show up, you better include it here!
|
||||
triggers: {
|
||||
[newFile.key]: newFile,
|
||||
},
|
||||
|
||||
// If you want your creates to show up, you better include it here!
|
||||
creates: {
|
||||
[uploadFileV10.key]: uploadFileV10,
|
||||
[uploadFileV9.key]: uploadFileV9,
|
||||
},
|
||||
};
|
||||
17
vendor/zapier-platform/example-apps/files/package.json
vendored
Normal file
17
vendor/zapier-platform/example-apps/files/package.json
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "files",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "jest --testTimeout 10000"
|
||||
},
|
||||
"dependencies": {
|
||||
"zapier-platform-core": "19.1.0",
|
||||
"form-data": "4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^26.6.3"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
60
vendor/zapier-platform/example-apps/files/test/creates.test.js
vendored
Normal file
60
vendor/zapier-platform/example-apps/files/test/creates.test.js
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* globals describe, expect, test */
|
||||
|
||||
const zapier = require('zapier-platform-core');
|
||||
|
||||
const App = require('../index');
|
||||
const appTester = zapier.createAppTester(App);
|
||||
zapier.tools.env.inject();
|
||||
|
||||
const CORE_VERSION = zapier.version.split('.').map((s) => parseInt(s));
|
||||
|
||||
const FILE_URL =
|
||||
'https://cdn.zapier.com/storage/files/f6679cf77afeaf6b8426de8d7b9642fc.pdf';
|
||||
|
||||
// This is what you get when doing `curl <FILE_URL> | sha1sum`
|
||||
const EXPECTED_SHA1 = '3cf58b42a0fb1b7cc58de8110096841ece967530';
|
||||
|
||||
describe('uploadFile', () => {
|
||||
test('upload file v10', async () => {
|
||||
if (CORE_VERSION[0] < 10) {
|
||||
console.warn(
|
||||
`skipped because this only works on core v10+ and you're on ${zapier.version}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const bundle = {
|
||||
inputData: {
|
||||
filename: 'sample.pdf',
|
||||
|
||||
// in production, this will be an hydration URL to the selected file's data
|
||||
file: FILE_URL,
|
||||
},
|
||||
};
|
||||
|
||||
const result = await appTester(
|
||||
App.creates.uploadFile_v10.operation.perform,
|
||||
bundle,
|
||||
);
|
||||
expect(result.filename).toBe('sample.pdf');
|
||||
expect(result.file.sha1).toBe(EXPECTED_SHA1);
|
||||
});
|
||||
|
||||
test('upload file v9', async () => {
|
||||
const bundle = {
|
||||
inputData: {
|
||||
filename: 'sample.pdf',
|
||||
|
||||
// in production, this will be an hydration URL to the selected file's data
|
||||
file: FILE_URL,
|
||||
},
|
||||
};
|
||||
|
||||
const result = await appTester(
|
||||
App.creates.uploadFile_v9.operation.perform,
|
||||
bundle,
|
||||
);
|
||||
expect(result.filename).toBe('sample.pdf');
|
||||
expect(result.file.sha1).toBe(EXPECTED_SHA1);
|
||||
});
|
||||
});
|
||||
27
vendor/zapier-platform/example-apps/files/test/hydrators.test.js
vendored
Normal file
27
vendor/zapier-platform/example-apps/files/test/hydrators.test.js
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* globals describe, expect, test */
|
||||
|
||||
const zapier = require('zapier-platform-core');
|
||||
|
||||
const App = require('../index');
|
||||
const appTester = zapier.createAppTester(App);
|
||||
zapier.tools.env.inject();
|
||||
|
||||
describe('downloadFile', () => {
|
||||
test('download file', async () => {
|
||||
if (!process.env.ZAPIER_DEPLOY_KEY) {
|
||||
console.warn('skipped as ZAPIER_DEPLOY_KEY is not defined');
|
||||
return;
|
||||
}
|
||||
|
||||
const bundle = {
|
||||
inputData: {
|
||||
url: 'https://httpbin.zapier-tooling.com/xml',
|
||||
},
|
||||
};
|
||||
|
||||
const url = await appTester(App.hydrators.downloadFile, bundle);
|
||||
expect(url).toContain(
|
||||
'https://zapier-dev-files.s3.amazonaws.com/cli-platform/',
|
||||
);
|
||||
});
|
||||
});
|
||||
26
vendor/zapier-platform/example-apps/files/test/triggers.test.js
vendored
Normal file
26
vendor/zapier-platform/example-apps/files/test/triggers.test.js
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* globals describe, expect, test */
|
||||
|
||||
const zapier = require('zapier-platform-core');
|
||||
|
||||
const App = require('../index');
|
||||
const appTester = zapier.createAppTester(App);
|
||||
zapier.tools.env.inject();
|
||||
|
||||
describe('newFile', () => {
|
||||
test('fetch files', async () => {
|
||||
const bundle = {};
|
||||
const results = await appTester(
|
||||
App.triggers.newFile.operation.perform,
|
||||
bundle,
|
||||
);
|
||||
|
||||
expect(results.length).toBeGreaterThan(0);
|
||||
|
||||
// The 'hydrate|||' thing how Zapier represents dehydrated data
|
||||
const firstFile = results[0];
|
||||
expect(firstFile).toEqual({
|
||||
id: expect.stringMatching(/^https:/),
|
||||
file: expect.stringMatching(/^hydrate\|\|\|/),
|
||||
});
|
||||
});
|
||||
});
|
||||
46
vendor/zapier-platform/example-apps/files/triggers/newFile.js
vendored
Normal file
46
vendor/zapier-platform/example-apps/files/triggers/newFile.js
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
const hydrators = require('../hydrators');
|
||||
|
||||
const perform = (z, bundle) => {
|
||||
// In reality you're more likely to get file info from a remote server. Here
|
||||
// we're hard coding some links just to demonstrate.
|
||||
const fileURLs = [
|
||||
'https://httpbin.zapier-tooling.com/image/png',
|
||||
'https://httpbin.zapier-tooling.com/image/jpeg',
|
||||
'https://httpbin.zapier-tooling.com/xml',
|
||||
];
|
||||
|
||||
return fileURLs.map((fileURL) => {
|
||||
const fileInfo = {
|
||||
id: fileURL,
|
||||
|
||||
// Make it possible to get the actual file contents if necessary. No need
|
||||
// to make the request to download files now when the trigger is run.
|
||||
file: z.dehydrateFile(hydrators.downloadFile, { url: fileURL }),
|
||||
};
|
||||
return fileInfo;
|
||||
});
|
||||
};
|
||||
|
||||
// We recommend writing your triggers separate like this and rolling them into
|
||||
// the App definition at the end.
|
||||
module.exports = {
|
||||
key: 'newFile',
|
||||
|
||||
// You'll want to provide some helpful display labels and descriptions
|
||||
// for users. Zapier will put them into the UX.
|
||||
noun: 'File',
|
||||
display: {
|
||||
label: 'New File',
|
||||
description: 'Triggers when a new file is added.',
|
||||
},
|
||||
|
||||
// `operation` is where the business logic goes.
|
||||
operation: {
|
||||
perform,
|
||||
|
||||
sample: {
|
||||
id: 'https://example.com/file.txt',
|
||||
file: 'content',
|
||||
},
|
||||
},
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue