@norbix.ai/cli 1.0.0 → 1.2.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.
@@ -0,0 +1,25 @@
1
+ import { Args } from '@oclif/core';
2
+ import { BaseCommand } from '../../../base.js';
3
+ import { templateBody, templateFlags } from '../../../lib/push.js';
4
+ export default class PushTemplateUpdate extends BaseCommand {
5
+ static description = `Replace a push template's name, channel, tags and content
6
+
7
+ The whole template is sent, so pass every language you want to keep.`;
8
+ static examples = [
9
+ '<%= config.bin %> push template update 66b2f0a1... --name Welcome --title "Hi" --body "Thanks for joining"',
10
+ ];
11
+ static args = {
12
+ id: Args.string({ required: true, description: 'Template ID' }),
13
+ };
14
+ static flags = templateFlags;
15
+ async run() {
16
+ const { args, flags } = await this.parse(PushTemplateUpdate);
17
+ const client = this.client(flags);
18
+ const res = await client.hub.notifications.updatePushTemplate({
19
+ ...(await templateBody(flags)),
20
+ viewId: args.id,
21
+ });
22
+ this.print(`Template ${args.id} updated.`);
23
+ return res;
24
+ }
25
+ }
@@ -0,0 +1,70 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { Flags } from '@oclif/core';
3
+ import { readJsonInput } from './json.js';
4
+ /**
5
+ * Read a JSON object from a flag: inline JSON, `-` for stdin, or `@path` for a
6
+ * file. Used by the push commands whose body is too rich for flags alone
7
+ * (template translations, provider credentials, campaign audiences).
8
+ */
9
+ export async function readJsonObject(value, flagName) {
10
+ const raw = value.startsWith('@') ? readFileSync(value.slice(1), 'utf8') : value;
11
+ const parsed = JSON.parse(await readJsonInput(raw, flagName));
12
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
13
+ throw new Error(`--${flagName} must be a JSON object`);
14
+ }
15
+ return parsed;
16
+ }
17
+ /** Turn repeated `--token key=value` flags into token mappings with the Custom resolver. */
18
+ export function parseTokens(values) {
19
+ if (!values?.length)
20
+ return undefined;
21
+ return values.map((pair) => {
22
+ const at = pair.indexOf('=');
23
+ if (at < 1)
24
+ throw new Error(`--token must look like key=value, got "${pair}"`);
25
+ return { key: pair.slice(0, at), value: pair.slice(at + 1), resolver: 'Custom' };
26
+ });
27
+ }
28
+ /**
29
+ * Build the template body. Either --translations (a JSON array, @file or -)
30
+ * for several languages, or --title + --body for one language.
31
+ */
32
+ export async function templateBody(flags) {
33
+ let translations;
34
+ if (flags.translations) {
35
+ const raw = flags.translations.startsWith('@') ? readFileSync(flags.translations.slice(1), 'utf8') : flags.translations;
36
+ translations = JSON.parse(await readJsonInput(raw, 'translations'));
37
+ if (!Array.isArray(translations))
38
+ throw new Error('--translations must be a JSON array');
39
+ }
40
+ else {
41
+ if (!flags.title || !flags.body) {
42
+ throw new Error('Pass --title and --body, or --translations for several languages.');
43
+ }
44
+ translations = [{ language: flags.language, content: { title: flags.title, body: flags.body } }];
45
+ }
46
+ return {
47
+ templateName: flags.name,
48
+ description: flags.description,
49
+ communicationChannel: flags.channel,
50
+ tags: flags.tag,
51
+ translations,
52
+ };
53
+ }
54
+ export const templateFlags = {
55
+ name: Flags.string({ required: true, description: 'Template name' }),
56
+ description: Flags.string({ description: 'What the template is for' }),
57
+ channel: Flags.string({
58
+ description: 'Communication channel',
59
+ options: ['Transactional', 'Marketing', 'System'],
60
+ default: 'Transactional',
61
+ }),
62
+ tag: Flags.string({ description: 'Tag (repeat for several)', multiple: true }),
63
+ language: Flags.string({ description: 'Language of --title / --body', default: 'en' }),
64
+ title: Flags.string({ description: 'Push title (Razor allowed)' }),
65
+ body: Flags.string({ description: 'Push body (Razor allowed)' }),
66
+ translations: Flags.string({
67
+ description: 'All languages as a JSON array of {language, content: {title, body}} — inline, @file or -',
68
+ exclusive: ['title', 'body'],
69
+ }),
70
+ };