@texisoft/create-nexus-plugin 0.0.0-stage → 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,78 @@
1
+ TEXISOFT PROPRIETARY LICENSE
2
+
3
+ Copyright (c) 2026 texisoft. All rights reserved.
4
+
5
+ This software, including its source code, documentation and associated
6
+ materials (the "Software"), is proprietary to texisoft ("Licensor"). It is made
7
+ available on public package registries for distribution convenience only.
8
+ Publication does NOT grant an open-source license and does NOT transfer or
9
+ waive any right of the Licensor.
10
+
11
+ 1. Limited permission
12
+ Subject to this license, you may install and run the Software solely to
13
+ develop, test, build and publish plugins for the Nexus Discord bot platform
14
+ operated by the Licensor ("Nexus"), and only for as long as you comply with
15
+ this license. This permission is personal, non-exclusive, non-transferable,
16
+ non-sublicensable and revocable at any time.
17
+
18
+ 2. Restrictions
19
+ Except where applicable law expressly forbids the restriction, you may not:
20
+ a) copy, modify, adapt, translate or create derivative works of the Software;
21
+ b) redistribute, publish, sell, rent, lease, sublicense or otherwise make
22
+ the Software or any part of it available to third parties, whether
23
+ modified or not, including re-publishing it to any package registry or
24
+ repository;
25
+ c) decompile, reverse engineer or attempt to derive source code, algorithms
26
+ or the sandbox, permission or protocol design, except for the source
27
+ that is delivered in readable form with the package, which remains
28
+ subject to this license;
29
+ d) use the Software, or knowledge gained from it, to build, operate or
30
+ support a platform, service or product that competes with or replaces
31
+ Nexus, or that is compatible with Nexus plugins;
32
+ e) circumvent, disable or probe the security, sandbox, permission, rate
33
+ limit, review or consent mechanisms of Nexus, or use the Software to
34
+ attack, overload or gain unauthorized access to Nexus or any third
35
+ party;
36
+ f) remove or alter copyright, license or attribution notices;
37
+ g) use the Software to train, fine-tune or evaluate machine-learning models,
38
+ or to build datasets for that purpose.
39
+
40
+ 3. Your plugins
41
+ Plugins you write remain yours. Submitting a plugin to Nexus is governed by
42
+ the Nexus developer terms, not by this license. Bundled portions of the
43
+ Software that the build tooling inserts into your plugin may be distributed
44
+ only as part of that plugin and only to Nexus.
45
+
46
+ 4. Ownership
47
+ The Software is licensed, not sold. The Licensor retains all right, title
48
+ and interest, including all intellectual property rights.
49
+
50
+ 5. Termination
51
+ This license ends automatically and without notice if you breach it. On
52
+ termination you must stop using the Software and delete all copies. The
53
+ Licensor may also withdraw this license at any time by publishing a notice
54
+ or removing the Software.
55
+
56
+ 6. No warranty
57
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
+ IMPLIED, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
59
+ NON-INFRINGEMENT, AVAILABILITY OR COMPATIBILITY WITH ANY FUTURE VERSION. THE
60
+ SOFTWARE IS A PRE-1.0 RELEASE AND ITS INTERFACES MAY CHANGE WITHOUT NOTICE.
61
+
62
+ 7. Limitation of liability
63
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE LICENSOR IS NOT LIABLE FOR ANY
64
+ INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES, LOSS OF
65
+ DATA, PROFITS OR GOODWILL, ARISING FROM OR RELATED TO THE SOFTWARE. THE
66
+ LICENSOR'S TOTAL LIABILITY IS LIMITED TO EUR 100, EXCEPT FOR LIABILITY THAT
67
+ CANNOT BE EXCLUDED UNDER APPLICABLE LAW (INTENT, GROSS NEGLIGENCE, INJURY
68
+ TO LIFE, BODY OR HEALTH, AND LIABILITY UNDER THE PRODUCT LIABILITY ACT).
69
+
70
+ 8. Governing law
71
+ This license is governed by the laws of the Federal Republic of Germany,
72
+ excluding its conflict-of-laws rules and the UN Convention on Contracts for
73
+ the International Sale of Goods. If you are a merchant or a legal entity,
74
+ the courts at the Licensor's registered seat have exclusive jurisdiction.
75
+
76
+ 9. Severability
77
+ If a provision is invalid, the remaining provisions stay in force and the
78
+ invalid provision is replaced by the closest valid one.
package/README.md CHANGED
@@ -1,3 +1,26 @@
1
- # Temporary Holding Version
1
+ # @texisoft/create-nexus-plugin
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Legt ein neues Nexus-Plugin an.
4
+
5
+ ```bash
6
+ npm create @texisoft/nexus-plugin mein-plugin
7
+ cd mein-plugin
8
+ npm install
9
+ npm test
10
+ ```
11
+
12
+ Du bekommst ein lauffähiges Projekt mit einem Beispiel-Command, Übersetzungen und einem Test:
13
+
14
+ ```
15
+ manifest.json id, Version, Berechtigungen, Commands, Sprachen
16
+ index.js export default definePlugin({ setup(ctx) { ... } })
17
+ locales/ Übersetzungen für ctx.t
18
+ test/ Tests mit dem Testkit
19
+ package.json SDK, CLI und Testkit als Abhängigkeiten
20
+ ```
21
+
22
+ Weiter geht es mit `npx nexus-plugin validate`, `npx nexus-plugin dev --guild <TEST_GUILD_ID>` und `npx nexus-plugin publish`. Was diese Befehle tun, steht in der README von `@texisoft/nexus-plugin-cli`.
23
+
24
+ ## Lizenz
25
+
26
+ Node.js 22 oder neuer. Das Paket ist proprietär, alle Rechte bleiben bei texisoft. Du darfst es nur nutzen, um Plugins für Nexus zu entwickeln, Genaueres steht in der `LICENSE`. Die Version ist noch 0.x, Schnittstellen können sich ändern.
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from 'node:path'
3
+ import { scaffoldPlugin } from '../src/scaffold.js'
4
+
5
+ const [id, ...rest] = process.argv.slice(2)
6
+
7
+ if (!id || id.startsWith('-')) {
8
+ process.stderr.write('Aufruf: npm create @texisoft/nexus-plugin <plugin-id> [Anzeigename]\n')
9
+ process.exit(2)
10
+ }
11
+
12
+ try {
13
+ const files = await scaffoldPlugin({ dir: resolve(process.cwd(), id), id, name: rest.join(' ') || undefined })
14
+ process.stdout.write(`Plugin "${id}" angelegt (${files.length} Dateien).\n\n cd ${id}\n npm install\n npm test\n npx nexus-plugin validate\n`)
15
+ } catch (error) {
16
+ process.stderr.write(`Fehler: ${error.message}\n`)
17
+ process.exit(1)
18
+ }
package/package.json CHANGED
@@ -1,6 +1,46 @@
1
1
  {
2
2
  "name": "@texisoft/create-nexus-plugin",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Gerüst für neue Nexus-Plugins (npm create @texisoft/nexus-plugin <id>).",
5
+ "keywords": [
6
+ "nexus",
7
+ "discord",
8
+ "discord-bot",
9
+ "plugin",
10
+ "texisoft"
11
+ ],
12
+ "license": "SEE LICENSE IN LICENSE",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/texisoft/discord-nexus-bot.git",
16
+ "directory": "packages/create-nexus-plugin"
17
+ },
18
+ "homepage": "https://github.com/texisoft/discord-nexus-bot/tree/master/packages/create-nexus-plugin",
19
+ "bugs": {
20
+ "url": "https://github.com/texisoft/discord-nexus-bot/issues"
21
+ },
22
+ "type": "module",
23
+ "bin": {
24
+ "create-nexus-plugin": "./bin/create-nexus-plugin.js"
25
+ },
26
+ "main": "./src/scaffold.js",
27
+ "exports": {
28
+ ".": "./src/scaffold.js"
29
+ },
30
+ "files": [
31
+ "bin",
32
+ "src",
33
+ "template",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "engines": {
38
+ "node": ">=22"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "dependencies": {
44
+ "@texisoft/nexus-plugin-sdk": "^0.1.0"
45
+ }
46
+ }
@@ -0,0 +1,58 @@
1
+ import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'
2
+ import { dirname, join, relative } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { PLUGIN_ID_REGEX } from '@texisoft/nexus-plugin-sdk'
5
+
6
+ export const TEMPLATE_DIR = fileURLToPath(new URL('../template', import.meta.url))
7
+
8
+ const RENAMES = { _gitignore: '.gitignore' }
9
+
10
+ function targetName(name) {
11
+ if (RENAMES[name]) return RENAMES[name]
12
+ return name.endsWith('.tpl') ? name.slice(0, -4) : name
13
+ }
14
+
15
+ function titleFromId(id) {
16
+ return id.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ')
17
+ }
18
+
19
+ async function walk(dir) {
20
+ const out = []
21
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
22
+ const full = join(dir, entry.name)
23
+ if (entry.isDirectory()) out.push(...await walk(full))
24
+ else out.push(full)
25
+ }
26
+ return out
27
+ }
28
+
29
+ async function assertEmpty(dir) {
30
+ try {
31
+ const info = await stat(dir)
32
+ if (!info.isDirectory()) throw new Error(`${dir} existiert und ist kein Verzeichnis`)
33
+ if ((await readdir(dir)).length > 0) throw new Error(`Zielverzeichnis ${dir} ist nicht leer`)
34
+ } catch (error) {
35
+ if (error.code !== 'ENOENT') throw error
36
+ }
37
+ }
38
+
39
+ export async function scaffoldPlugin({ dir, id, name, templateDir = TEMPLATE_DIR }) {
40
+ if (!PLUGIN_ID_REGEX.test(id)) {
41
+ throw new Error(`Ungültige Plugin-ID "${id}": erlaubt sind ^[a-z][a-z0-9-]{2,31}$`)
42
+ }
43
+ await assertEmpty(dir)
44
+ const values = { __ID__: id, __NAME__: name ?? titleFromId(id) }
45
+ const created = []
46
+ for (const file of await walk(templateDir)) {
47
+ const rel = relative(templateDir, file)
48
+ const parts = rel.split(/[\\/]/)
49
+ parts[parts.length - 1] = targetName(parts[parts.length - 1])
50
+ const target = join(dir, ...parts)
51
+ let content = await readFile(file, 'utf8')
52
+ for (const [token, value] of Object.entries(values)) content = content.replaceAll(token, value)
53
+ await mkdir(dirname(target), { recursive: true })
54
+ await writeFile(target, content)
55
+ created.push(parts.join('/'))
56
+ }
57
+ return created.sort()
58
+ }
@@ -0,0 +1,14 @@
1
+ # __NAME__
2
+
3
+ Nexus-Plugin (`__ID__`).
4
+
5
+ ```
6
+ npm install
7
+ npm test Tests mit dem Test-Kit
8
+ npx nexus-plugin validate Manifest, Permissions und Muster prüfen
9
+ npx nexus-plugin login Schlüssel einmalig speichern (nie im Projekt)
10
+ npx nexus-plugin dev Plugin lokal entwickeln, verbunden mit einer Test-Guild
11
+ npx nexus-plugin publish Bauen, hochladen und zur Prüfung einreichen
12
+ ```
13
+
14
+ Die vollständige Anleitung steht in `docs/PLUGINS-DEV.md` des Nexus-Repositories.
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ dist
3
+ .nexus-plugin
4
+ .env
5
+ .env.*
@@ -0,0 +1,10 @@
1
+ import { definePlugin } from '@texisoft/nexus-plugin-sdk'
2
+
3
+ export default definePlugin({
4
+ setup(ctx) {
5
+ ctx.commands.on('hello', async (interaction, api) => {
6
+ const n = await ctx.storage.kv.incr('hello:count')
7
+ await api.reply({ content: ctx.t('hello.reply', { name: interaction.user.username, n }), ephemeral: true })
8
+ })
9
+ }
10
+ })
@@ -0,0 +1,3 @@
1
+ {
2
+ "hello.reply": "Hallo {name}! Das war Aufruf Nummer {n}."
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "hello.reply": "Hello {name}! That was call number {n}."
3
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "__ID__",
3
+ "name": "__NAME__",
4
+ "version": "0.1.0",
5
+ "sdkVersion": "^0.1.0",
6
+ "description": "Beschreibe hier, was dein Plugin tut.",
7
+ "permissions": {
8
+ "commandsMax": 1,
9
+ "storageQuotaKb": 16
10
+ },
11
+ "commands": [
12
+ { "name": "hello", "description": "Sagt Hallo und zählt mit", "options": [] }
13
+ ],
14
+ "locales": { "default": "de", "supported": ["de", "en"] },
15
+ "main": "index.js"
16
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "__ID__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "test": "node --test",
8
+ "validate": "nexus-plugin validate",
9
+ "build": "nexus-plugin build",
10
+ "dev": "nexus-plugin dev",
11
+ "publish:plugin": "nexus-plugin publish"
12
+ },
13
+ "dependencies": {
14
+ "@texisoft/nexus-plugin-sdk": "^0.1.0"
15
+ },
16
+ "devDependencies": {
17
+ "@texisoft/nexus-plugin-cli": "^0.1.0",
18
+ "@texisoft/nexus-plugin-testkit": "^0.1.0"
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ import { test } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { createProjectHarness } from '@texisoft/nexus-plugin-testkit'
5
+
6
+ const dir = fileURLToPath(new URL('..', import.meta.url))
7
+
8
+ test('/hello antwortet und zählt hoch', async () => {
9
+ const harness = await createProjectHarness(dir)
10
+ const first = await harness.runCommand('hello')
11
+ assert.equal(first.ok, true)
12
+ assert.match(first.reply.content, /Nummer 1\./)
13
+ const second = await harness.runCommand('hello')
14
+ assert.match(second.reply.content, /Nummer 2\./)
15
+ assert.equal(harness.storage.get('hello:count'), 2)
16
+ })