@foxtware/mineral 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.creds.yml.sample +22 -1
- package/api/loop/loop.constants.js +7 -0
- package/api/loop/loop.utils.js +43 -0
- package/api/loop/loopAllowlistItemsGet.js +42 -0
- package/api/loop/loopBlocklistItemsGet.js +46 -0
- package/api/loop/loopDestinationsGet.js +42 -0
- package/api/loop/loopGet.js +143 -0
- package/api/loop/loopReturnGet.js +73 -0
- package/api/loop/loopReturnsGet.js +46 -0
- package/api/peoplevox/peoplevox.sessions.js +87 -0
- package/api/peoplevox/peoplevox.utils.js +7 -15
- package/api/shopify/shopifyCollectionGet.js +1 -1
- package/api/shopify/shopifyTagsAdd.js +1 -1
- package/api/shopify/shopifyTagsRemove.js +1 -1
- package/api/stripe/_example.js +48 -0
- package/api/stripe/stripe.constants.js +5 -0
- package/api/stripe/stripe.utils.js +47 -0
- package/api/stripe/stripeCardCharge.js +98 -0
- package/api/stripe/stripeCardTokenCreate.js +70 -0
- package/api/stripe/stripeChargeCapture.js +63 -0
- package/api/stripe/stripeChargeCreate.js +70 -0
- package/api/stripe/stripeChargeGet.js +51 -0
- package/api/stripe/stripeChargesGet.js +52 -0
- package/api/stripe/stripeRefundCreate.js +64 -0
- package/api/stripe/stripeRefundGet.js +51 -0
- package/api/stripe/stripeRefundsGet.js +52 -0
- package/api/stripe/stripeTokenGet.js +51 -0
- package/api/supabase/supabase.utils.js +52 -0
- package/api/supabase/supabaseRowDelete.js +95 -0
- package/api/supabase/supabaseRowGet.js +58 -0
- package/api/supabase/supabaseRowInsert.js +56 -0
- package/api/supabase/supabaseRowUpdate.js +58 -0
- package/api/supabase/supabaseRpc.js +61 -0
- package/api/supabase/supabaseTableGet.js +44 -0
- package/api/supabase/supabaseTableGetAll.js +86 -0
- package/api/upstash/upstash.utils.js +36 -0
- package/api/upstash/upstashDel.js +46 -0
- package/api/upstash/upstashExists.js +46 -0
- package/api/upstash/upstashGet.js +46 -0
- package/api/upstash/upstashSet.js +64 -0
- package/api/utils.js +52 -1
- package/api/workable/workable.constants.js +3 -0
- package/api/workable/workable.utils.js +46 -0
- package/api/workable/workableGet.js +146 -0
- package/api/workable/workableJobCandidateCreate.js +87 -0
- package/api/workable/workableJobGet.js +52 -0
- package/api/workable/workableJobMembersGet.js +52 -0
- package/api/workable/workableJobStagesGet.js +52 -0
- package/api/workable/workableJobsGet.js +78 -0
- package/bin/mineral.js +6 -0
- package/hosting/.hosting.yml.sample +9 -11
- package/hosting/copyCredsToEnv.js +58 -2
- package/hosting/deployFromHostingYml.js +9 -2
- package/hosting/generateHosted.js +22 -2
- package/hosting/hosting.utils.js +3 -2
- package/hosting/hostingPreview.js +160 -0
- package/hosting/wrappers.js +1 -1
- package/package.json +9 -2
- package/server.utils.js +1 -0
|
@@ -1,7 +1,59 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const yaml = require('yaml');
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const getValueAtCredsPath = (creds, pathParts) => {
|
|
5
|
+
let current = creds;
|
|
6
|
+
|
|
7
|
+
for (const pathPart of pathParts) {
|
|
8
|
+
if (current == null || typeof current !== 'object' || !(pathPart in current)) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
current = current[pathPart];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return current;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const setValueAtCredsPath = (target, pathParts, value) => {
|
|
19
|
+
let current = target;
|
|
20
|
+
|
|
21
|
+
for (let index = 0; index < pathParts.length - 1; index++) {
|
|
22
|
+
const pathPart = pathParts[index];
|
|
23
|
+
|
|
24
|
+
if (!(pathPart in current) || typeof current[pathPart] !== 'object' || current[pathPart] === null) {
|
|
25
|
+
current[pathPart] = {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
current = current[pathPart];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
current[pathParts[pathParts.length - 1]] = value;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const filterCredsByPaths = (creds, includeCredsPaths) => {
|
|
35
|
+
const filteredCreds = {};
|
|
36
|
+
|
|
37
|
+
for (const credsPath of includeCredsPaths) {
|
|
38
|
+
if (typeof credsPath !== 'string' || !credsPath.trim()) {
|
|
39
|
+
throw new Error(`Invalid include_creds_paths entry: ${ credsPath }`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const pathParts = credsPath.split('.');
|
|
43
|
+
const value = getValueAtCredsPath(creds, pathParts);
|
|
44
|
+
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
throw new Error(`Missing creds path "${ credsPath }" in .creds.yml`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setValueAtCredsPath(filteredCreds, pathParts, value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return filteredCreds;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const copyCredsToEnv = (workspace, options = {}) => {
|
|
56
|
+
const { includeCredsPaths } = options;
|
|
5
57
|
const normalizedWorkspace = workspace.replace(/\/$/, '');
|
|
6
58
|
const credsPath = `${ normalizedWorkspace }/.creds.yml`;
|
|
7
59
|
const envPath = `${ normalizedWorkspace }/.env`;
|
|
@@ -12,7 +64,10 @@ const copyCredsToEnv = (workspace) => {
|
|
|
12
64
|
|
|
13
65
|
const credsText = fs.readFileSync(credsPath, 'utf8');
|
|
14
66
|
const credsFromYml = yaml.parse(credsText);
|
|
15
|
-
const
|
|
67
|
+
const credsForEnv = includeCredsPaths?.length
|
|
68
|
+
? filterCredsByPaths(credsFromYml, includeCredsPaths)
|
|
69
|
+
: credsFromYml;
|
|
70
|
+
const newCredsLine = `CREDS=${ JSON.stringify(credsForEnv) }`;
|
|
16
71
|
|
|
17
72
|
let envFileContents = '';
|
|
18
73
|
if (fs.existsSync(envPath)) {
|
|
@@ -45,4 +100,5 @@ if (require.main === module) {
|
|
|
45
100
|
|
|
46
101
|
module.exports = {
|
|
47
102
|
copyCredsToEnv,
|
|
103
|
+
filterCredsByPaths,
|
|
48
104
|
};
|
|
@@ -109,6 +109,7 @@ const deployFunction = async ({
|
|
|
109
109
|
groups,
|
|
110
110
|
before_wrappers,
|
|
111
111
|
after_wrappers,
|
|
112
|
+
include_creds_paths,
|
|
112
113
|
source,
|
|
113
114
|
env,
|
|
114
115
|
...gcloudArgs
|
|
@@ -197,7 +198,6 @@ const deployFunction = async ({
|
|
|
197
198
|
const deployFromHostingYml = async (options = {}) => {
|
|
198
199
|
const config = getHostConfig(options);
|
|
199
200
|
setWorkspace(config.workspace);
|
|
200
|
-
ensureWorkspaceEnvForDeploy(config.workspace);
|
|
201
201
|
loadWorkspaceEnv();
|
|
202
202
|
|
|
203
203
|
const hostingConfig = readHostingYml(config.workspace);
|
|
@@ -235,9 +235,16 @@ const deployFromHostingYml = async (options = {}) => {
|
|
|
235
235
|
return;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
const functionConfig = functions[functionName];
|
|
239
|
+
const includeCredsPaths = Array.isArray(functionConfig.include_creds_paths)
|
|
240
|
+
? functionConfig.include_creds_paths
|
|
241
|
+
: undefined;
|
|
242
|
+
|
|
243
|
+
ensureWorkspaceEnvForDeploy(config.workspace, { includeCredsPaths });
|
|
244
|
+
|
|
238
245
|
await deployFunction({
|
|
239
246
|
functionName,
|
|
240
|
-
functionConfig
|
|
247
|
+
functionConfig,
|
|
241
248
|
googleCloudInfo,
|
|
242
249
|
workspace: config.workspace,
|
|
243
250
|
});
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const { wrapHostedFunction } = require('./hosting.utils');
|
|
3
3
|
|
|
4
|
+
const requirePathForHostedJs = (modulePath) => {
|
|
5
|
+
if (modulePath === './hosting/wrappers.js') {
|
|
6
|
+
return './wrappers.js';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (modulePath.startsWith('./api/')) {
|
|
10
|
+
return `../${ modulePath.slice(2) }`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return modulePath;
|
|
14
|
+
};
|
|
15
|
+
|
|
4
16
|
const formatResolvedWrapperForHostedJs = ({ modulePath, wrapperName }) => (
|
|
5
|
-
`require('${ modulePath }').${ wrapperName }`
|
|
17
|
+
`require('${ requirePathForHostedJs(modulePath) }').${ wrapperName }`
|
|
6
18
|
);
|
|
7
19
|
|
|
8
20
|
const formatWrapperList = (resolvedWrappers = []) => {
|
|
@@ -53,7 +65,7 @@ const generateHostedJs = ({
|
|
|
53
65
|
});
|
|
54
66
|
|
|
55
67
|
exportLines.push(
|
|
56
|
-
` ${ hostedName }: wrapHostedFunction(() => require('${ requirePath }'), '${ handlerName }'${ wrappersArg }),`,
|
|
68
|
+
` ${ hostedName }: wrapHostedFunction(() => require('${ requirePathForHostedJs(requirePath) }'), '${ handlerName }'${ wrappersArg }),`,
|
|
57
69
|
);
|
|
58
70
|
}
|
|
59
71
|
|
|
@@ -77,6 +89,14 @@ const writeHostedJs = ({
|
|
|
77
89
|
});
|
|
78
90
|
|
|
79
91
|
fs.mkdirSync(getHostingDir(workspace), { recursive: true });
|
|
92
|
+
|
|
93
|
+
if (fs.existsSync(hostedPath)) {
|
|
94
|
+
const existingContent = fs.readFileSync(hostedPath, 'utf8');
|
|
95
|
+
if (existingContent === content) {
|
|
96
|
+
return hostedPath;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
80
100
|
fs.writeFileSync(hostedPath, content);
|
|
81
101
|
return hostedPath;
|
|
82
102
|
};
|
package/hosting/hosting.utils.js
CHANGED
|
@@ -189,11 +189,12 @@ const readHostingYml = (workspace) => {
|
|
|
189
189
|
return hostingConfig;
|
|
190
190
|
};
|
|
191
191
|
|
|
192
|
-
const ensureWorkspaceEnvForDeploy = (workspace) => {
|
|
192
|
+
const ensureWorkspaceEnvForDeploy = (workspace, options = {}) => {
|
|
193
|
+
const { includeCredsPaths } = options;
|
|
193
194
|
const { copyCredsToEnv } = require('./copyCredsToEnv');
|
|
194
195
|
const envPath = `${ workspace.replace(/\/$/, '') }/.env`;
|
|
195
196
|
|
|
196
|
-
copyCredsToEnv(workspace);
|
|
197
|
+
copyCredsToEnv(workspace, { includeCredsPaths });
|
|
197
198
|
|
|
198
199
|
if (!fs.existsSync(envPath)) {
|
|
199
200
|
throw new Error(`Missing .env in workspace: ${ workspace }`);
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const { createRequire } = require('module');
|
|
3
|
+
const { respondJson, errorToReadable } = require('../server.utils');
|
|
4
|
+
const { getWorkspace, setWorkspace, loadWorkspaceEnv, toAbsolutePath } = require('../api/workspace');
|
|
5
|
+
const { getApiDirs, readCliFlag } = require('../cli');
|
|
6
|
+
const { loadHandlers } = require('../server');
|
|
7
|
+
const {
|
|
8
|
+
readHostingYml,
|
|
9
|
+
resolveHostedHandlersForDeploy,
|
|
10
|
+
wrapHostedFunction,
|
|
11
|
+
} = require('./hosting.utils');
|
|
12
|
+
const { copyCredsToEnv } = require('./copyCredsToEnv');
|
|
13
|
+
|
|
14
|
+
const getConfig = (options = {}) => ({
|
|
15
|
+
port: Number(options.port ?? process.env.PORT ?? 8000),
|
|
16
|
+
workspace: toAbsolutePath(
|
|
17
|
+
options.workspace
|
|
18
|
+
?? readCliFlag('--workspace')
|
|
19
|
+
?? process.env.MINERAL_WORKSPACE
|
|
20
|
+
?? process.cwd(),
|
|
21
|
+
),
|
|
22
|
+
api_dirs: getApiDirs(options),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const handlerByRouteName = (handlers) => {
|
|
26
|
+
const byName = new Map();
|
|
27
|
+
|
|
28
|
+
for (const handler of handlers.values()) {
|
|
29
|
+
byName.set(handler.routeName, handler);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return byName;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const loadHostedRoutes = (config) => {
|
|
36
|
+
const { functions } = readHostingYml(config.workspace);
|
|
37
|
+
const handlers = loadHandlers({
|
|
38
|
+
...config,
|
|
39
|
+
host_mode: true,
|
|
40
|
+
});
|
|
41
|
+
const handlersByName = handlerByRouteName(handlers);
|
|
42
|
+
const hostedHandlers = resolveHostedHandlersForDeploy({
|
|
43
|
+
functions,
|
|
44
|
+
workspace: config.workspace,
|
|
45
|
+
handlersByName,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const workspaceRequire = createRequire(`${ config.workspace.replace(/\/$/, '') }/package.json`);
|
|
49
|
+
const routes = new Map();
|
|
50
|
+
|
|
51
|
+
for (const hostedHandler of hostedHandlers) {
|
|
52
|
+
const {
|
|
53
|
+
hostedName,
|
|
54
|
+
handlerName,
|
|
55
|
+
resolvedBeforeWrappers = [],
|
|
56
|
+
resolvedAfterWrappers = [],
|
|
57
|
+
requirePath,
|
|
58
|
+
} = hostedHandler;
|
|
59
|
+
|
|
60
|
+
const beforeWrappers = resolvedBeforeWrappers.map(({ modulePath, wrapperName }) => (
|
|
61
|
+
workspaceRequire(modulePath)[wrapperName]
|
|
62
|
+
));
|
|
63
|
+
const afterWrappers = resolvedAfterWrappers.map(({ modulePath, wrapperName }) => (
|
|
64
|
+
workspaceRequire(modulePath)[wrapperName]
|
|
65
|
+
));
|
|
66
|
+
|
|
67
|
+
routes.set(
|
|
68
|
+
`/${ hostedName }`,
|
|
69
|
+
wrapHostedFunction(
|
|
70
|
+
() => workspaceRequire(requirePath),
|
|
71
|
+
handlerName,
|
|
72
|
+
{
|
|
73
|
+
beforeWrappers,
|
|
74
|
+
afterWrappers,
|
|
75
|
+
},
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return routes;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const createHostedPreviewServer = (handlers) => http.createServer(async (req, res) => {
|
|
84
|
+
if (req.method === 'GET' && req.url === '/') {
|
|
85
|
+
respondJson(res, 200, {
|
|
86
|
+
ok: true,
|
|
87
|
+
data: {
|
|
88
|
+
mode: 'hosting_preview',
|
|
89
|
+
routes: [...handlers.keys()].sort(),
|
|
90
|
+
workspace: getWorkspace(),
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const route = (req.url || '/').split('?')[0];
|
|
97
|
+
const handler = handlers.get(route);
|
|
98
|
+
|
|
99
|
+
if (!handler) {
|
|
100
|
+
respondJson(res, 404, {
|
|
101
|
+
ok: false,
|
|
102
|
+
error: {
|
|
103
|
+
code: 'NOT_FOUND',
|
|
104
|
+
message: `No hosted handler found for route ${ route }`,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await handler(req, res);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (res.headersSent) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
respondJson(res, 500, {
|
|
118
|
+
ok: false,
|
|
119
|
+
error: {
|
|
120
|
+
code: 'UNHANDLED_ERROR',
|
|
121
|
+
message: 'Unhandled server error.',
|
|
122
|
+
details: errorToReadable(error),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const startHostingPreview = (options = {}) => {
|
|
129
|
+
process.env.HOSTED = 'true';
|
|
130
|
+
|
|
131
|
+
const config = getConfig(options);
|
|
132
|
+
|
|
133
|
+
setWorkspace(config.workspace);
|
|
134
|
+
copyCredsToEnv(config.workspace);
|
|
135
|
+
loadWorkspaceEnv();
|
|
136
|
+
|
|
137
|
+
const handlers = loadHostedRoutes(config);
|
|
138
|
+
const server = createHostedPreviewServer(handlers);
|
|
139
|
+
|
|
140
|
+
server.listen(config.port, () => {
|
|
141
|
+
console.log(`Hosting preview running on port ${ config.port }`);
|
|
142
|
+
console.log(`Workspace: ${ config.workspace }`);
|
|
143
|
+
console.log('Hosted routes:');
|
|
144
|
+
|
|
145
|
+
for (const route of [...handlers.keys()].sort()) {
|
|
146
|
+
console.log(route);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return server;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
startHostingPreview,
|
|
155
|
+
loadHostedRoutes,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (require.main === module) {
|
|
159
|
+
startHostingPreview();
|
|
160
|
+
}
|
package/hosting/wrappers.js
CHANGED
|
@@ -22,7 +22,7 @@ const allowCrossOriginCallsAndHandleOptions = async (req, res) => {
|
|
|
22
22
|
|
|
23
23
|
res.setHeader('Access-Control-Allow-Origin', origin || '*');
|
|
24
24
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
25
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, x-wf-token, x-wf-value');
|
|
25
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, x-wf-token, x-wf-value, x-wf-app');
|
|
26
26
|
|
|
27
27
|
if (req.method === 'OPTIONS') {
|
|
28
28
|
res.writeHead(204);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foxtware/mineral",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"bin": {
|
|
5
5
|
"mineral": "bin/mineral.js"
|
|
6
6
|
},
|
|
@@ -10,17 +10,24 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"creds_to_env": "node hosting/copyCredsToEnv.js",
|
|
13
|
-
"dev": "node --watch --watch-path=./api --watch-path=./server.js --watch-path=./server.utils.js --watch-path=./.creds.yml server.js",
|
|
13
|
+
"dev": "node --watch --watch-path=./api --watch-path=./server.js --watch-path=./server.utils.js --watch-path=./hosting --watch-path=./.creds.yml server.js",
|
|
14
|
+
"hosting_preview": "node --watch --watch-path=./api --watch-path=./hosting/.hosting.yml --watch-path=./hosting/wrappers.js --watch-path=./.creds.yml hosting/hostingPreview.js",
|
|
15
|
+
"tunnel": "ngrok http http://localhost:8000",
|
|
14
16
|
"new": "node _build_scripts/createNewFunction.js",
|
|
15
17
|
"serve": "PORT=8100 node server.js",
|
|
16
18
|
"start": "node server.js",
|
|
17
19
|
"npm:publish": "node _build_scripts/publish.js"
|
|
18
20
|
},
|
|
19
21
|
"dependencies": {
|
|
22
|
+
"@supabase/supabase-js": "^2.55.0",
|
|
23
|
+
"@upstash/redis": "^1.28.4",
|
|
20
24
|
"csvtojson": "^2.0.14",
|
|
21
25
|
"dotenv": "^17.2.0",
|
|
22
26
|
"json-2-csv": "^5.5.9",
|
|
23
27
|
"xml2js": "^0.6.2",
|
|
24
28
|
"yaml": "^2.9.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"ngrok": "^5.0.0-beta.2"
|
|
25
32
|
}
|
|
26
33
|
}
|
package/server.utils.js
CHANGED
|
@@ -258,6 +258,7 @@ const funcApi = (func, config = {}) => {
|
|
|
258
258
|
|
|
259
259
|
let callArgs = requestContext.args;
|
|
260
260
|
if (passThroughReq) {
|
|
261
|
+
requestContext.req.body = modifiedBody;
|
|
261
262
|
callArgs = [requestContext.req];
|
|
262
263
|
} else if (passThroughBody) {
|
|
263
264
|
callArgs = [modifiedBody];
|