@friggframework/core 2.0.0--canary.696.5d9f1be.0 → 2.0.0--canary.698.b1a2d30.0

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.
Files changed (30) hide show
  1. package/integrations/data-defined/README.md +31 -1
  2. package/integrations/data-defined/capabilities/AUDIT.md +451 -0
  3. package/integrations/data-defined/capabilities/asana.capabilities.json +22 -13
  4. package/integrations/data-defined/capabilities/fathom.capabilities.json +16 -6
  5. package/integrations/data-defined/capabilities/hubspot.capabilities.json +78 -27
  6. package/integrations/data-defined/capabilities/linear.capabilities.json +30 -10
  7. package/integrations/data-defined/capabilities/phone.capabilities.json +24 -7
  8. package/integrations/data-defined/capabilities/pipedrive.capabilities.json +26 -11
  9. package/integrations/data-defined/capabilities/salesforce.capabilities.json +64 -18
  10. package/integrations/data-defined/capabilities/slack.capabilities.json +12 -5
  11. package/integrations/data-defined/capabilities/stripe.capabilities.json +28 -10
  12. package/integrations/data-defined/data-defined-integration.js +2 -2
  13. package/integrations/data-defined/examples/asana-slack.definition.json +4 -5
  14. package/integrations/data-defined/examples/hubspot-slack.definition.json +4 -4
  15. package/integrations/data-defined/examples/klaviyo-hubspot.definition.json +1 -4
  16. package/integrations/data-defined/examples/phone-hubspot.definition.json +1 -5
  17. package/integrations/data-defined/expressions.js +2 -0
  18. package/integrations/data-defined/index.js +6 -0
  19. package/integrations/data-defined/manifests.js +18 -0
  20. package/integrations/data-defined/renderers/common.js +67 -0
  21. package/integrations/data-defined/renderers/html.js +129 -0
  22. package/integrations/data-defined/renderers/hubspot.js +54 -0
  23. package/integrations/data-defined/renderers/preview.js +154 -0
  24. package/integrations/data-defined/renderers/slack.js +146 -0
  25. package/integrations/data-defined/runtime.js +17 -2
  26. package/integrations/data-defined/schema/capability-manifest.v0.1.schema.json +40 -0
  27. package/integrations/data-defined/scripts/check-manifests.js +220 -0
  28. package/integrations/data-defined/tests/helpers-fake-crm.js +11 -6
  29. package/integrations/data-defined/validate.js +6 -0
  30. package/package.json +5 -5
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Check capability manifests against the real API modules they describe (ADR-063 phase 4: real manifests).
4
+ *
5
+ * node scripts/check-manifests.js <modules-dir> [<modules-dir> ...]
6
+ * node scripts/check-manifests.js --manifests capabilities/ --json ~/api-module-library/packages
7
+ * node scripts/check-manifests.js --stub-missing --strict ~/api-module-library/packages
8
+ *
9
+ * For every manifest it finds the module (a directory named <module> or api-module-<module>, or whose package.json
10
+ * name ends in that, up to three levels under each given directory; the first one that loads wins), loads its Api
11
+ * class and checks, with no network and no instance, on the prototype:
12
+ * - every capability's `method` exists (a capability marked `status: "unimplemented"` must NOT have it: the
13
+ * manifest would be stale);
14
+ * - the arguments fit the method's declared parameters: `args` no longer than the parameter list, and a
15
+ * capability with no `args` (called with one object) is not a method that needs two or more positional ones;
16
+ * - `webhook.verify` names a method that exists.
17
+ *
18
+ * Exit codes: 0 every method found (unimplemented capabilities and modules with no source are reported, not failed,
19
+ * unless --strict) · 1 a mismatch · 2 could not run (bad arguments, no manifests).
20
+ *
21
+ * --manifests <dir> manifests to check (default: ../capabilities)
22
+ * --json machine-readable result on stdout
23
+ * --strict unimplemented capabilities, unloadable modules and modules not found fail too
24
+ * --stub-missing load modules whose own dependencies are not installed (jsforce, stripe, @linear/sdk ...) by
25
+ * standing in for the missing packages; enough to read the Api's methods, never to call them
26
+ */
27
+ const fs = require('fs');
28
+ const path = require('path');
29
+ const Module = require('module');
30
+
31
+ const FOUND = 'ok';
32
+
33
+ /** Parameters of a function as written: [{ name, optional }]. Reads the source, so it is a heuristic for the arity check. */
34
+ function parametersOf(fn) {
35
+ const src = Function.prototype.toString.call(fn);
36
+ const bare = /^(?:async\s+)?([\w$]+)\s*=>/.exec(src);
37
+ if (bare) return [{ text: bare[1], optional: false }];
38
+ const open = src.indexOf('(');
39
+ if (open < 0) return [];
40
+ let depth = 0, i = open, cur = '';
41
+ const parts = [];
42
+ for (; i < src.length; i++) {
43
+ const c = src[i];
44
+ if ('([{'.includes(c)) { depth++; if (depth === 1) continue; }
45
+ if (')]}'.includes(c)) { depth--; if (depth === 0) break; }
46
+ if (c === ',' && depth === 1) { parts.push(cur); cur = ''; } else cur += c;
47
+ }
48
+ if (cur.trim()) parts.push(cur);
49
+ return parts.map((p) => p.replace(/\/\*[\s\S]*?\*\//g, '').trim()).filter(Boolean).map((p) => ({ text: p.replace(/\s+/g, ' '), optional: /^\.\.\./.test(p) || p.includes('=') || /^[\w$]+\s*\?/.test(p) }));
50
+ }
51
+
52
+ function methodOf(Api, name) {
53
+ for (let p = Api && Api.prototype; p && p !== Object.prototype; p = Object.getPrototypeOf(p)) {
54
+ const d = Object.getOwnPropertyDescriptor(p, name);
55
+ if (d) return typeof d.value === 'function' ? d.value : null;
56
+ }
57
+ return null;
58
+ }
59
+
60
+ const signatureOf = (fn) => `(${parametersOf(fn).map((p) => p.text).join(', ')})`;
61
+
62
+ const looksLikeModule = (dir) => ['package.json', 'index.js', 'api.js'].some((f) => fs.existsSync(path.join(dir, f)));
63
+
64
+ /** Directories that could be the module: name match, up to `depth` levels below root. */
65
+ function candidates(root, moduleName, depth = 3) {
66
+ const found = [];
67
+ const isMatch = (dir) => {
68
+ const base = path.basename(dir);
69
+ if (base === moduleName || base === `api-module-${moduleName}`) return true;
70
+ try { return JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')).name?.endsWith(`api-module-${moduleName}`); } catch { return false; }
71
+ };
72
+ const walk = (dir, level) => {
73
+ if (level > depth) return;
74
+ let entries;
75
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
76
+ for (const e of entries) {
77
+ if (!e.isDirectory() || e.name === 'node_modules' || e.name.startsWith('.')) continue;
78
+ const full = path.join(dir, e.name);
79
+ if (isMatch(full) && looksLikeModule(full)) found.push(full);
80
+ else walk(full, level + 1);
81
+ }
82
+ };
83
+ if (isMatch(root) && looksLikeModule(root)) found.push(root);
84
+ walk(root, 1);
85
+ return found;
86
+ }
87
+
88
+ /** Stand-ins for dependencies that are not installed, so an Api's methods can be read. Restored by the caller. */
89
+ function stubMissingDependencies() {
90
+ const original = Module._load;
91
+ const stub = () => new Proxy(function stubbed() {}, { get: (t, k) => (k === '__esModule' ? false : k === 'prototype' ? t.prototype : t[k] || (t[k] = stub())), construct: () => ({}), apply: () => stub() });
92
+ Module._load = function load(request, ...rest) {
93
+ try { return original.call(this, request, ...rest); } catch (e) {
94
+ if (e && e.code === 'MODULE_NOT_FOUND' && !request.startsWith('.') && !path.isAbsolute(request)) return stub();
95
+ throw e;
96
+ }
97
+ };
98
+ return () => { Module._load = original; };
99
+ }
100
+
101
+ function loadApi(dir) {
102
+ const attempts = [dir, path.join(dir, 'api.js'), path.join(dir, 'src', 'api.js'), path.join(dir, 'dist', 'api.js')];
103
+ let firstError;
104
+ for (const target of attempts) {
105
+ try {
106
+ const mod = require(target);
107
+ const Api = mod.Api || mod.API || mod.Definition?.API || (typeof mod === 'function' ? mod : null);
108
+ if (typeof Api === 'function' && Api.prototype) return { Api, from: path.relative(dir, require.resolve(target)) || '.' };
109
+ firstError = firstError || new Error('exports no Api class');
110
+ } catch (e) { firstError = firstError || e; } // the first failure is the module's own; later ones are only missing fallbacks
111
+ }
112
+ return { error: (firstError?.message || 'cannot load').split('\n')[0] };
113
+ }
114
+
115
+ /**
116
+ * @param {Record<string, object>} manifests module -> manifest
117
+ * @param {string[]} roots directories to look for the modules in
118
+ * @returns {Array<{module, package?, source?, state, message?, rows: Array<{capability, method, state, signature?, args?, note?}>}>}
119
+ */
120
+ function checkManifests(manifests, roots, { stubMissing = false } = {}) {
121
+ const restore = stubMissing ? stubMissingDependencies() : null;
122
+ try {
123
+ return Object.values(manifests).map((m) => {
124
+ const result = { module: m.module, package: m.package, state: FOUND, rows: [] };
125
+ const dirs = roots.flatMap((r) => candidates(path.resolve(r), m.module));
126
+ if (!dirs.length) return { ...result, state: 'no-module', message: `No directory named ${m.module} or api-module-${m.module} under ${roots.join(', ')}` };
127
+ let loaded, failures = [];
128
+ for (const dir of dirs) {
129
+ const l = loadApi(dir);
130
+ if (l.Api) { loaded = { ...l, dir }; break; }
131
+ failures.push(`${dir}: ${l.error}`);
132
+ }
133
+ if (!loaded) return { ...result, state: 'unloadable', message: failures.join('; ') };
134
+ result.source = loaded.dir;
135
+ const { Api } = loaded;
136
+ for (const [name, c] of Object.entries(m.capabilities || {})) {
137
+ const fn = methodOf(Api, c.method);
138
+ const row = { capability: name, method: c.method };
139
+ if (c.status === 'unimplemented') {
140
+ row.state = fn ? 'stale-unimplemented' : 'unimplemented';
141
+ row.note = fn ? `Marked unimplemented, but ${c.method}${signatureOf(fn)} exists: ${c.note || 'no note says why it cannot be used'}` : c.note;
142
+ if (fn) row.signature = signatureOf(fn);
143
+ } else if (!fn) {
144
+ row.state = 'missing';
145
+ } else {
146
+ row.signature = signatureOf(fn);
147
+ const params = parametersOf(fn);
148
+ const required = params.filter((p) => !p.optional).length;
149
+ if (c.args) {
150
+ row.args = c.args.map((a) => (typeof a === 'string' ? a : `=${JSON.stringify(a.value)}`)).join(', ');
151
+ row.state = c.args.length > params.length && !params.some((p) => p.text.startsWith('...')) ? 'arity' : 'ok';
152
+ if (row.state === 'arity') row.note = `Passes ${c.args.length} arguments; ${c.method} declares ${params.length}`;
153
+ } else {
154
+ row.state = required > 1 ? 'arity' : 'ok';
155
+ if (row.state === 'arity') row.note = `Called with one object; ${c.method} needs ${required} positional arguments (add args)`;
156
+ }
157
+ if (c.note) row.note = [row.note, c.note].filter(Boolean).join('. ');
158
+ }
159
+ result.rows.push(row);
160
+ }
161
+ if (m.webhook?.verify) {
162
+ const fn = methodOf(Api, m.webhook.verify);
163
+ const marked = m.webhook.status === 'unimplemented';
164
+ result.rows.push({ capability: 'webhook.verify', method: m.webhook.verify, state: fn ? (marked ? 'stale-unimplemented' : 'ok') : marked ? 'unimplemented' : 'missing', ...(fn ? { signature: signatureOf(fn) } : {}), ...(m.webhook.note ? { note: m.webhook.note } : {}) });
165
+ }
166
+ return result;
167
+ });
168
+ } finally { if (restore) restore(); }
169
+ }
170
+
171
+ // stale-unimplemented is soft: the method exists but the note may say why it cannot be used as the capability is shaped.
172
+ const BAD = new Set(['missing', 'arity']);
173
+ const SOFT = new Set(['unimplemented', 'stale-unimplemented', 'unloadable', 'no-module']);
174
+
175
+ function summarise(results) {
176
+ const counts = {};
177
+ for (const r of results) {
178
+ counts[r.state] = (counts[r.state] || 0) + (r.state === FOUND ? 0 : 1);
179
+ for (const row of r.rows) counts[row.state] = (counts[row.state] || 0) + 1;
180
+ }
181
+ const mismatches = results.flatMap((r) => r.rows.filter((x) => BAD.has(x.state)));
182
+ const soft = results.filter((r) => SOFT.has(r.state)).length + results.flatMap((r) => r.rows).filter((x) => SOFT.has(x.state)).length;
183
+ return { counts, mismatches: mismatches.length, soft };
184
+ }
185
+
186
+ function main(argv) {
187
+ const args = [...argv];
188
+ const flag = (n) => { const i = args.indexOf(n); if (i < 0) return false; args.splice(i, 1); return true; };
189
+ const option = (n) => { const i = args.indexOf(n); if (i < 0) return null; const v = args[i + 1]; args.splice(i, 2); return v; };
190
+ const strict = flag('--strict'), asJson = flag('--json'), stubMissing = flag('--stub-missing');
191
+ const manifestDir = option('--manifests') || path.join(__dirname, '..', 'capabilities');
192
+ const unknown = args.find((a) => a.startsWith('--'));
193
+ if (unknown) { console.error(`Unknown option ${unknown}`); return 2; }
194
+ if (!args.length) { console.error('Usage: check-manifests.js [--manifests dir] [--json] [--strict] [--stub-missing] <modules-dir> [...]'); return 2; }
195
+ for (const r of args) if (!fs.existsSync(r)) { console.error(`No such directory: ${r}`); return 2; }
196
+ if (!fs.existsSync(manifestDir)) { console.error(`No such directory: ${manifestDir}`); return 2; }
197
+ const manifests = {};
198
+ for (const f of fs.readdirSync(manifestDir).filter((x) => x.endsWith('.capabilities.json'))) {
199
+ try { const m = JSON.parse(fs.readFileSync(path.join(manifestDir, f), 'utf8')); manifests[m.module] = m; } catch (e) { console.error(`${f}: not valid JSON (${e.message})`); return 2; }
200
+ }
201
+ if (!Object.keys(manifests).length) { console.error(`No *.capabilities.json in ${manifestDir}`); return 2; }
202
+
203
+ const results = checkManifests(manifests, args, { stubMissing });
204
+ const sum = summarise(results);
205
+ const failed = sum.mismatches > 0 || (strict && sum.soft > 0);
206
+ if (asJson) process.stdout.write(`${JSON.stringify({ valid: !failed, strict, summary: sum, results }, null, 2)}\n`);
207
+ else {
208
+ for (const r of results) {
209
+ if (r.state !== FOUND) { console.log(`${strict ? 'FAIL' : 'skip'} ${r.module.padEnd(12)} ${r.state}: ${r.message}`); continue; }
210
+ const bad = r.rows.filter((x) => BAD.has(x.state)).length;
211
+ console.log(`${bad ? 'FAIL' : 'ok '} ${r.module.padEnd(12)} ${r.rows.filter((x) => x.state === 'ok').length}/${r.rows.length} ok (${path.relative(process.cwd(), r.source) || '.'})`);
212
+ for (const x of r.rows.filter((y) => y.state !== 'ok')) console.log(` ${x.state.padEnd(20)} ${x.capability} -> ${x.method}${x.note ? ` ${x.note}` : ''}`);
213
+ }
214
+ console.log(`\n${results.length} manifests: ${sum.mismatches} mismatches, ${sum.soft} unverifiable or unimplemented${strict ? ' (strict)' : ''}`);
215
+ }
216
+ return failed ? 1 : 0;
217
+ }
218
+
219
+ if (require.main === module) process.exit(main(process.argv.slice(2)));
220
+ module.exports = { checkManifests, summarise, parametersOf, methodOf, candidates };
@@ -1,4 +1,9 @@
1
- /** In-memory HubSpot and Phone APIs shaped like the real ones as their manifests describe them. Test helper. */
1
+ /**
2
+ * In-memory HubSpot and Phone APIs with the real Api classes' call shapes (the manifests' `args`): HubSpot's
3
+ * getContactById(id), createContact(properties), updateContact(id, properties); Phone's getContact(id) and
4
+ * updateContact(id, { defaultFields }). searchContacts is on both only because the sync tests need a search; neither
5
+ * real Api has one (the manifests mark contact.search unimplemented). Test helper.
6
+ */
2
7
  /** A fake API: records by id, a write log, and the methods the manifest names. */
3
8
  function hubspotApi() {
4
9
  const records = new Map();
@@ -6,7 +11,7 @@ function hubspotApi() {
6
11
  const api = {
7
12
  records, writes: [],
8
13
  seed(props, extra = {}) { const id = String(++n); records.set(id, { id, properties: { ...props }, updatedAt: extra.updatedAt || '2026-10-01T00:00:00Z' }); return id; },
9
- async getContactById({ id }) { return records.get(String(id)) || null; },
14
+ async getContactById(id) { return records.get(String(id)) || null; },
10
15
  async searchContacts({ email, phone }) { return [...records.values()].filter((r) => (email && r.properties.email === email) || (phone && r.properties.phone === phone)); },
11
16
  async listContacts({ after, limit = 100, updatedSince }) {
12
17
  const all = [...records.values()].filter((r) => !updatedSince || Date.parse(r.updatedAt) > Date.parse(updatedSince));
@@ -14,8 +19,8 @@ function hubspotApi() {
14
19
  const page = all.slice(start, start + limit);
15
20
  return { results: page, ...(start + limit < all.length ? { paging: { next: { after: String(start + limit) } } } : {}) };
16
21
  },
17
- async createContact({ properties }) { api.writes.push(['create', properties]); const id = api.seed(properties, { updatedAt: '2026-10-02T00:00:00Z' }); return records.get(id); },
18
- async updateContact({ id, properties }) { api.writes.push(['update', id, properties]); const r = records.get(String(id)); Object.assign(r.properties, properties); r.updatedAt = '2026-10-03T00:00:00Z'; return r; },
22
+ async createContact(properties) { api.writes.push(['create', properties]); const id = api.seed(properties, { updatedAt: '2026-10-02T00:00:00Z' }); return records.get(id); },
23
+ async updateContact(id, properties) { api.writes.push(['update', id, properties]); const r = records.get(String(id)); Object.assign(r.properties, properties); r.updatedAt = '2026-10-03T00:00:00Z'; return r; },
19
24
  };
20
25
  return api;
21
26
  }
@@ -25,7 +30,7 @@ function phoneApi() {
25
30
  const api = {
26
31
  records, writes: [], searches: [],
27
32
  seed(fields, extra = {}) { const id = `CT${++n}`; records.set(id, { id, defaultFields: JSON.parse(JSON.stringify(fields)), ...extra }); return id; },
28
- async getContact({ id }) { return records.get(id) || null; },
33
+ async getContact(id) { return records.get(id) || null; },
29
34
  async searchContacts(args) {
30
35
  api.searches.push(args);
31
36
  return [...records.values()].filter((r) => (args.phone && r.defaultFields.phoneNumbers?.[0]?.value === args.phone) || (args.email && r.defaultFields.emails?.[0]?.value === args.email));
@@ -36,7 +41,7 @@ function phoneApi() {
36
41
  return { data: all.slice(start, start + maxResults), ...(start + maxResults < all.length ? { nextPageToken: String(start + maxResults) } : {}) };
37
42
  },
38
43
  async createContact({ defaultFields, externalId }) { api.writes.push(['create', defaultFields, externalId]); const id = api.seed(defaultFields, { externalId }); return records.get(id); },
39
- async updateContact({ id, defaultFields }) { api.writes.push(['update', id, defaultFields]); const r = records.get(id); r.defaultFields = { ...r.defaultFields, ...defaultFields }; return r; },
44
+ async updateContact(id, { defaultFields }) { api.writes.push(['update', id, defaultFields]); const r = records.get(id); r.defaultFields = { ...r.defaultFields, ...defaultFields }; return r; },
40
45
  };
41
46
  return api;
42
47
  }
@@ -100,6 +100,7 @@ function validate(def, manifests = {}, { codeMethods } = {}) {
100
100
  const list = manifestOf[mk].options?.[ok];
101
101
  if (!list) { err(p, `Module "${mk}" has no option list "${ok}"`); return; }
102
102
  const inputs = list.inputs || {};
103
+ if (manifestOf[mk].capabilities?.[list.capability]?.status === 'unimplemented') warn(p, `Option list ${ref.source} reads ${list.capability}, which is unimplemented in the ${mk} Api; the dropdown will not load`);
103
104
  for (const [name, spec] of Object.entries(inputs)) if (spec.required && !(name in (ref.with || {}))) err(`${p}.with.${name}`, `Option list ${ref.source} needs input "${name}"`);
104
105
  for (const [name, v] of Object.entries(ref.with || {})) {
105
106
  if (!(name in inputs)) { err(`${p}.with.${name}`, `Option list ${ref.source} takes no input "${name}"`); continue; }
@@ -177,6 +178,9 @@ function validate(def, manifests = {}, { codeMethods } = {}) {
177
178
  const toName = `${to.k}.${to.o}`;
178
179
  if (!fs) { err(`${p}.${from === src ? 'source' : 'target'}`, `${fromName} declares no sync block (objects.${from.o}.sync), so it cannot be read`); continue; }
179
180
  if (!ts) { err(`${p}.${to === tgt ? 'target' : 'source'}`, `${toName} declares no sync block (objects.${to.o}.sync), so it cannot be written`); continue; }
181
+ for (const [spec, man, nm, where] of [[fs, manifestOf[from.k], fromName, from === src ? 'source' : 'target'], [ts, manifestOf[to.k], toName, to === tgt ? 'target' : 'source']]) {
182
+ for (const op of Object.values(spec)) if (op?.capability && man.capabilities?.[op.capability]?.status === 'unimplemented') warn(`${p}.${where}`, `${nm} syncs through ${op.capability}, which is unimplemented in the ${man.module} Api`);
183
+ }
180
184
  if (!ts.create && !ts.update) err(`${p}.${to === tgt ? 'target' : 'source'}`, `${toName} has neither sync.create nor sync.update`);
181
185
  if ((s.backfill?.trigger || 'none') !== 'none' && !fs.list && from === src) err(`${p}.backfill`, `A backfill pages through ${fromName}, which has no sync.list`);
182
186
  // A two-way backfill also reads the target when it can list; when it cannot, it reads only the source.
@@ -305,6 +309,7 @@ function validate(def, manifests = {}, { codeMethods } = {}) {
305
309
  const c = man.capabilities?.[cap.capability];
306
310
  if (!c) err(`${p}.use`, `Module "${cap.module}" (${man.module}) has no capability "${cap.capability}"`);
307
311
  else {
312
+ if (c.status === 'unimplemented') warn(`${p}.use`, `${st.use} is unimplemented in the ${man.module} Api${c.note ? ` (${c.note})` : ''}; this step will fail at run time until the module adds it`);
308
313
  for (const [name, spec] of Object.entries(c.input || {})) if (spec.required && !(name in args)) err(`${p}.with.${name}`, `Required by ${st.use}`);
309
314
  for (const name of Object.keys(args)) if (c.input && !(name in c.input)) err(`${p}.with.${name}`, `${st.use} takes no argument "${name}"`);
310
315
  }
@@ -329,6 +334,7 @@ function validate(def, manifests = {}, { codeMethods } = {}) {
329
334
  if (t.type === 'webhook') {
330
335
  if (!manifestOf[t.module]) err(`${p}.trigger.module`, `Unknown module key "${t.module}"`);
331
336
  else if (!manifestOf[t.module].events?.[t.topic]) err(`${p}.trigger.topic`, `Module "${t.module}" emits no event "${t.topic}"`);
337
+ else if (manifestOf[t.module].webhook?.status === 'unimplemented' && (manifestOf[t.module].events[t.topic].delivery || 'webhook') === 'webhook') warn(`${p}.trigger`, `${t.module} events arrive by webhook, but the ${manifestOf[t.module].module} Api has no ${manifestOf[t.module].webhook.verify || 'verify'} method, so every delivery fails signature verification`);
332
338
  }
333
339
  if (t.type === 'schedule') {
334
340
  if ((t.cron === undefined) === (t.every === undefined)) err(`${p}.trigger`, 'Give exactly one of cron or every');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.696.5d9f1be.0",
4
+ "version": "2.0.0--canary.698.b1a2d30.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
7
7
  "@aws-sdk/client-kms": "^3.588.0",
@@ -47,9 +47,9 @@
47
47
  }
48
48
  },
49
49
  "devDependencies": {
50
- "@friggframework/eslint-config": "2.0.0--canary.696.5d9f1be.0",
51
- "@friggframework/prettier-config": "2.0.0--canary.696.5d9f1be.0",
52
- "@friggframework/test": "2.0.0--canary.696.5d9f1be.0",
50
+ "@friggframework/eslint-config": "2.0.0--canary.698.b1a2d30.0",
51
+ "@friggframework/prettier-config": "2.0.0--canary.698.b1a2d30.0",
52
+ "@friggframework/test": "2.0.0--canary.698.b1a2d30.0",
53
53
  "@prisma/client": "^6.19.3",
54
54
  "@types/lodash": "4.17.15",
55
55
  "@typescript-eslint/eslint-plugin": "^8.0.0",
@@ -90,5 +90,5 @@
90
90
  "publishConfig": {
91
91
  "access": "public"
92
92
  },
93
- "gitHead": "5d9f1be29b1cec33fd7ca6ec81b831a3c5a9be48"
93
+ "gitHead": "b1a2d30f3296992d698742a0c0a99b916c7fbfbe"
94
94
  }