@xeplr/actions 2.2.1 → 2.2.2
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/README.md +3 -1
- package/lib/builtins/index.js +2 -0
- package/lib/builtins/push-send.js +58 -0
- package/package.json +23 -19
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ Everything else is an **optional peer**, required only when an action actually u
|
|
|
26
26
|
| `mailparser` | `email-read` (unless `body: 'none'`), `email-download-attachments` |
|
|
27
27
|
| `nodemailer` (^10.0.13 — up to 10.0.5 has high-severity advisories) | `email-send` with its own connection |
|
|
28
28
|
| `@xeplr/email` | `email-send` with `templateName` |
|
|
29
|
+
| `@xeplr/push` | `push-send` (the host sets it up at boot: `push.init({ knex })`) |
|
|
29
30
|
| `knex` | the knex meta store |
|
|
30
31
|
| `mongodb`, `ssh2-sftp-client`, `exceljs` | declared, but their drivers/sources are not implemented |
|
|
31
32
|
|
|
@@ -121,7 +122,7 @@ The input is checked exactly as a run checks it.
|
|
|
121
122
|
|
|
122
123
|
| previewed (reads, up to 5) | example only (writes or sends; never run) |
|
|
123
124
|
|---|---|
|
|
124
|
-
| `db-fetch` (through the run's own cursor, then stops; nothing spooled), `db-list-tables` / `-views` / `-procedures` / `-columns`, `file-list`, `file-read`, `data-operation` (the run itself: it only computes), `email-read` (the mailbox opened **read-only**, IMAP `EXAMINE`, so nothing is marked read) | `file-move`, `file-delete`, `email-send`, `email-move`, `email-delete`, `email-download-email`, `email-download-attachments`, `export-table`, `export-pages`, `db-procedure` (a procedure may write) |
|
|
125
|
+
| `db-fetch` (through the run's own cursor, then stops; nothing spooled), `db-list-tables` / `-views` / `-procedures` / `-columns`, `file-list`, `file-read`, `data-operation` (the run itself: it only computes), `email-read` (the mailbox opened **read-only**, IMAP `EXAMINE`, so nothing is marked read) | `file-move`, `file-delete`, `email-send`, `push-send`, `email-move`, `email-delete`, `email-download-email`, `email-download-attachments`, `export-table`, `export-pages`, `db-procedure` (a procedure may write) |
|
|
125
126
|
|
|
126
127
|
Neither: `db-push`, `db-move`, `http-request` (an outside system, which may change something), `spawn-program`, `file-upload`; a designer asks for an example by hand. `test/previews.test.js` checks it on a real folder, file and Postgres: five rows read and no file spooled, the real count kept, a deleting step's file still there.
|
|
127
128
|
|
|
@@ -144,6 +145,7 @@ Register the ones you want (`register(actions.builtins.dbFetch)`) or pass a modu
|
|
|
144
145
|
| `dbListColumns` | `db-list-columns` | `{ columns }` — `name`, `dataType`, `udtName` and `maxLength` (characters; `-1` is SQL Server `(max)`, `null` when it has none) for one table. |
|
|
145
146
|
| `fileUpload` | `file-upload` | Read a file (`sourceType`, `sourcePath`), parse it (`format`), load it into `targetTable` (`dbType`, `dbConnection`) as a New table, Append or Replace (`mode`, see [Import modes](#import-modes)). Passes `system.onProgress` (`{ rowsRead, batches, rowsWritten }`, per batch) and `system.signal` (stop) to the uploader, as `db-move` does. |
|
|
146
147
|
| `sendEmail` | `email-send` | Send one message. See [Email](#email). |
|
|
148
|
+
| `pushSend` | `push-send` | A push notification on people's phones and computers, even with the app closed, by `emails` and/or `userIds`: `title` (required), `body`, `url` (a page of the app a tap opens), `tag`. Returns `{ devices, sent, removed, failed }`. Through [`@xeplr/push`](https://www.npmjs.com/package/@xeplr/push), which the host sets up. |
|
|
147
149
|
| `emailRead` | `email-read` | List messages, newest first, with `unread_only`, `limit` (1–1000, default 50), `since`, `from_equals`, `from_contains`, `subject_contains`, `body: 'full' \| 'text' \| 'none'`, optional NDJSON spooling. |
|
|
148
150
|
| `emailMove` | `email-move` | Move a message (`messageId`, `folder`) to `toFolder`. |
|
|
149
151
|
| `emailDelete` | `email-delete` | Flag `\Deleted` **and expunge** — permanent, not a move to Trash. |
|
package/lib/builtins/index.js
CHANGED
|
@@ -22,6 +22,8 @@ module.exports = {
|
|
|
22
22
|
dataOperation: require('./data-operation'),
|
|
23
23
|
spawnProgram: require('./spawn-program'),
|
|
24
24
|
sendEmail: require('./send-email'),
|
|
25
|
+
// A notification on people's devices (Web Push) — peer @xeplr/push.
|
|
26
|
+
pushSend: require('./push-send'),
|
|
25
27
|
|
|
26
28
|
// DB actions — factory-shaped (call fileUpload({ metaKnex }) to get a
|
|
27
29
|
// registerable module) so the Knex handle for the meta store binds at
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// push-send action — a notification on people's phones and computers, even
|
|
2
|
+
// with the app closed, through @xeplr/push (Web Push).
|
|
3
|
+
//
|
|
4
|
+
// Peer dep: `@xeplr/push`, lazy-required here, so an install that never
|
|
5
|
+
// pushes does not need it. The host app sets it up once at boot —
|
|
6
|
+
// push.init({ knex }) with its VAPID keys — and this step only sends.
|
|
7
|
+
//
|
|
8
|
+
// WHO: account ids (`userIds`) and/or emails (`emails`) — every device each of
|
|
9
|
+
// them switched on, each device once. Nobody to send to is refused, rather
|
|
10
|
+
// than "succeeding" with nothing sent.
|
|
11
|
+
//
|
|
12
|
+
// WHERE A TAP GOES: `url` is a page of the app ("/orders/{params.id}"). A full
|
|
13
|
+
// address to another site is replaced by the app's home by @xeplr/push, so a
|
|
14
|
+
// step can never send people off somewhere else.
|
|
15
|
+
|
|
16
|
+
function asList(v) {
|
|
17
|
+
if (v === undefined || v === null || v === '') return [];
|
|
18
|
+
return (Array.isArray(v) ? v : [v]).map(function(x) { return String(x).trim(); }).filter(Boolean);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
name: 'push-send',
|
|
23
|
+
// It sends, so it is never previewed.
|
|
24
|
+
example: { devices: 2, sent: 2, removed: 0, failed: 0 },
|
|
25
|
+
description: 'Send a push notification to people\'s phones and computers (Web Push, through @xeplr/push) — by account id or email. A tap opens the page given.',
|
|
26
|
+
requires: [], // @xeplr/push checked at runtime
|
|
27
|
+
|
|
28
|
+
inputSchema: [
|
|
29
|
+
{ name: 'emails', type: 'array', order: 1,
|
|
30
|
+
description: 'Who gets it, by email. A bare string is accepted and wrapped.' },
|
|
31
|
+
{ name: 'userIds', type: 'array', order: 2,
|
|
32
|
+
description: 'Who gets it, by account id — instead of, or as well as, emails.' },
|
|
33
|
+
{ name: 'title', type: 'string', required: true, order: 3,
|
|
34
|
+
description: 'The first line, e.g. "RTO: #{params.orderNumber}". At most 120 characters.' },
|
|
35
|
+
{ name: 'body', type: 'string', order: 4,
|
|
36
|
+
description: 'Under it. At most 300 characters.' },
|
|
37
|
+
{ name: 'url', type: 'string', order: 5,
|
|
38
|
+
description: 'The page of the app a tap opens, e.g. /orders/{params.id}. Leave empty for the home page.' },
|
|
39
|
+
{ name: 'tag', type: 'string', order: 6, group: 'Message options',
|
|
40
|
+
description: 'A new notification with the same tag replaces the one shown, so repeats stack as one.' }
|
|
41
|
+
],
|
|
42
|
+
|
|
43
|
+
execute: async function(ctx) {
|
|
44
|
+
var input = ctx.input || {};
|
|
45
|
+
var push;
|
|
46
|
+
try {
|
|
47
|
+
push = require('@xeplr/push');
|
|
48
|
+
} catch (_) {
|
|
49
|
+
throw new Error("push-send: '@xeplr/push' is not installed. Run: npm install @xeplr/push — and set it up at boot with push.init({ knex }).");
|
|
50
|
+
}
|
|
51
|
+
if (!push.enabled || !push.enabled()) {
|
|
52
|
+
throw new Error('push-send: push is not set up on this server — the host must call push.init() with PUSH_VAPID_PUBLIC_KEY / PUSH_VAPID_PRIVATE_KEY / PUSH_VAPID_SUBJECT (npx xeplr-push keys).');
|
|
53
|
+
}
|
|
54
|
+
var target = { emails: asList(input.emails), userIds: asList(input.userIds) };
|
|
55
|
+
if (!target.emails.length && !target.userIds.length) throw new Error('push-send: say who gets it — emails or userIds.');
|
|
56
|
+
return push.send(target, { title: input.title, body: input.body, url: input.url, tag: input.tag });
|
|
57
|
+
}
|
|
58
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xeplr/actions",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "Named-action registry with typed inputs and safe invocation — plus built-in actions for HTTP, DB, files, email, spawn",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"@duckdb/node-api": "1.5.5-r.3",
|
|
43
43
|
"@xeplr/db": "^1.1.0",
|
|
44
44
|
"@xeplr/email": "^1.0.0",
|
|
45
|
+
"@xeplr/push": "^1.0.0",
|
|
45
46
|
"@xeplr/utils": "^1.0.0",
|
|
46
47
|
"csv-parse": "^7.0.2",
|
|
47
48
|
"dejavu-fonts-ttf": "^2.37.3",
|
|
@@ -61,61 +62,64 @@
|
|
|
61
62
|
"unzipper": "^0.12.5"
|
|
62
63
|
},
|
|
63
64
|
"peerDependenciesMeta": {
|
|
64
|
-
"@xeplr/utils": {
|
|
65
|
-
"optional": true
|
|
66
|
-
},
|
|
67
65
|
"@duckdb/node-api": {
|
|
68
66
|
"optional": true
|
|
69
67
|
},
|
|
70
|
-
"
|
|
68
|
+
"@xeplr/email": {
|
|
71
69
|
"optional": true
|
|
72
70
|
},
|
|
73
|
-
"
|
|
71
|
+
"@xeplr/push": {
|
|
74
72
|
"optional": true
|
|
75
73
|
},
|
|
76
|
-
"
|
|
74
|
+
"@xeplr/utils": {
|
|
77
75
|
"optional": true
|
|
78
76
|
},
|
|
79
|
-
"
|
|
77
|
+
"csv-parse": {
|
|
80
78
|
"optional": true
|
|
81
79
|
},
|
|
82
|
-
"
|
|
80
|
+
"dejavu-fonts-ttf": {
|
|
83
81
|
"optional": true
|
|
84
82
|
},
|
|
85
83
|
"exceljs": {
|
|
86
84
|
"optional": true
|
|
87
85
|
},
|
|
88
|
-
"
|
|
86
|
+
"fflate": {
|
|
89
87
|
"optional": true
|
|
90
88
|
},
|
|
91
|
-
"
|
|
89
|
+
"imapflow": {
|
|
92
90
|
"optional": true
|
|
93
91
|
},
|
|
94
|
-
"
|
|
92
|
+
"knex": {
|
|
95
93
|
"optional": true
|
|
96
94
|
},
|
|
97
|
-
"
|
|
95
|
+
"mailparser": {
|
|
98
96
|
"optional": true
|
|
99
97
|
},
|
|
100
|
-
"
|
|
98
|
+
"mongodb": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"mssql": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"mysql2": {
|
|
101
105
|
"optional": true
|
|
102
106
|
},
|
|
103
107
|
"nodemailer": {
|
|
104
108
|
"optional": true
|
|
105
109
|
},
|
|
106
|
-
"
|
|
110
|
+
"pdfkit": {
|
|
107
111
|
"optional": true
|
|
108
112
|
},
|
|
109
|
-
"
|
|
113
|
+
"pg": {
|
|
110
114
|
"optional": true
|
|
111
115
|
},
|
|
112
|
-
"
|
|
116
|
+
"saxes": {
|
|
113
117
|
"optional": true
|
|
114
118
|
},
|
|
115
|
-
"
|
|
119
|
+
"ssh2-sftp-client": {
|
|
116
120
|
"optional": true
|
|
117
121
|
},
|
|
118
|
-
"
|
|
122
|
+
"unzipper": {
|
|
119
123
|
"optional": true
|
|
120
124
|
}
|
|
121
125
|
},
|