@nself/plugin-sdk 1.2.4

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 (41) hide show
  1. package/README.md +45 -0
  2. package/dist/context/db.d.ts +26 -0
  3. package/dist/context/db.d.ts.map +1 -0
  4. package/dist/context/db.js +38 -0
  5. package/dist/context/db.js.map +1 -0
  6. package/dist/context/env.d.ts +24 -0
  7. package/dist/context/env.d.ts.map +1 -0
  8. package/dist/context/env.js +48 -0
  9. package/dist/context/env.js.map +1 -0
  10. package/dist/context/hasura.d.ts +27 -0
  11. package/dist/context/hasura.d.ts.map +1 -0
  12. package/dist/context/hasura.js +74 -0
  13. package/dist/context/hasura.js.map +1 -0
  14. package/dist/context/http.d.ts +34 -0
  15. package/dist/context/http.d.ts.map +1 -0
  16. package/dist/context/http.js +78 -0
  17. package/dist/context/http.js.map +1 -0
  18. package/dist/context/logger.d.ts +14 -0
  19. package/dist/context/logger.d.ts.map +1 -0
  20. package/dist/context/logger.js +28 -0
  21. package/dist/context/logger.js.map +1 -0
  22. package/dist/context/nginx.d.ts +25 -0
  23. package/dist/context/nginx.d.ts.map +1 -0
  24. package/dist/context/nginx.js +30 -0
  25. package/dist/context/nginx.js.map +1 -0
  26. package/dist/index.d.ts +41 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +39 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/manifest/parser.d.ts +43 -0
  31. package/dist/manifest/parser.d.ts.map +1 -0
  32. package/dist/manifest/parser.js +79 -0
  33. package/dist/manifest/parser.js.map +1 -0
  34. package/dist/runner.d.ts +110 -0
  35. package/dist/runner.d.ts.map +1 -0
  36. package/dist/runner.js +32 -0
  37. package/dist/runner.js.map +1 -0
  38. package/package.json +71 -0
  39. package/templates/package.json +18 -0
  40. package/templates/plugin.yaml +11 -0
  41. package/templates/src/index.ts +42 -0
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @nself/plugin-sdk
2
+
3
+ TypeScript/Node.js plugin authoring SDK for [nSelf](https://nself.org). Parity with
4
+ [plugin-sdk-go](https://github.com/nself-org/plugin-sdk-go) v0.1.0.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ pnpm add @nself/plugin-sdk
10
+ ```
11
+
12
+ ## Quick start
13
+
14
+ ```ts
15
+ import { definePlugin, type PluginContext } from '@nself/plugin-sdk'
16
+
17
+ export default definePlugin({
18
+ name: 'my-notify',
19
+ version: '1.0.0',
20
+
21
+ async install(ctx: PluginContext) {
22
+ await ctx.env.require(['SMTP_HOST', 'SMTP_PORT'])
23
+ },
24
+
25
+ async start(ctx: PluginContext) {
26
+ const app = ctx.http.createApp()
27
+ app.post('/notify/send', myHandler)
28
+ ctx.http.listen(ctx.port)
29
+ },
30
+
31
+ async health(ctx: PluginContext) {
32
+ return ctx.http.ping('/notify/healthz')
33
+ },
34
+ })
35
+ ```
36
+
37
+ ## Scaffold a plugin
38
+
39
+ ```bash
40
+ nself plugin new my-plugin --lang typescript
41
+ ```
42
+
43
+ ## License
44
+
45
+ MIT
@@ -0,0 +1,26 @@
1
+ /**
2
+ * PostgreSQL helper — migration-time DDL only.
3
+ * Mirrors db.Pool in plugin-sdk-go: wraps pg driver, exposes runSQL().
4
+ * NOT for query-time use — plugins must talk to Hasura GraphQL at runtime.
5
+ */
6
+ /** Minimal row result from a migration query. */
7
+ export interface SqlResult {
8
+ rowCount: number;
9
+ rows: Record<string, unknown>[];
10
+ }
11
+ export interface DatabaseHelper {
12
+ /**
13
+ * runSQL executes raw SQL. Use only in install/migrate/uninstall hooks.
14
+ * Never call during request handling — that goes through Hasura.
15
+ */
16
+ runSQL(sql: string, params?: unknown[]): Promise<SqlResult>;
17
+ /** Close the underlying connection pool. Called automatically by the runner. */
18
+ close(): Promise<void>;
19
+ }
20
+ export interface DatabaseHelperOptions {
21
+ databaseUrl: string;
22
+ }
23
+ export declare function createDatabaseHelper(opts: DatabaseHelperOptions): Promise<DatabaseHelper>;
24
+ /** Stub implementation for use in unit tests — no real DB needed. */
25
+ export declare function createDatabaseHelperStub(): DatabaseHelper;
26
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/context/db.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iDAAiD;AACjD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IAE3D,gFAAgF;IAChF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAoB/F;AAED,qEAAqE;AACrE,wBAAgB,wBAAwB,IAAI,cAAc,CAOzD"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ /**
3
+ * PostgreSQL helper — migration-time DDL only.
4
+ * Mirrors db.Pool in plugin-sdk-go: wraps pg driver, exposes runSQL().
5
+ * NOT for query-time use — plugins must talk to Hasura GraphQL at runtime.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createDatabaseHelper = createDatabaseHelper;
9
+ exports.createDatabaseHelperStub = createDatabaseHelperStub;
10
+ async function createDatabaseHelper(opts) {
11
+ // Dynamic import so pg remains a peer dep (optional at install time).
12
+ // Plugins that don't run migrations never need pg installed.
13
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
14
+ const { Pool } = require('pg');
15
+ const pool = new Pool({ connectionString: opts.databaseUrl });
16
+ return {
17
+ async runSQL(sql, params) {
18
+ const res = await pool.query(sql, params);
19
+ return {
20
+ rowCount: res.rowCount ?? 0,
21
+ rows: res.rows,
22
+ };
23
+ },
24
+ async close() {
25
+ await pool.end();
26
+ },
27
+ };
28
+ }
29
+ /** Stub implementation for use in unit tests — no real DB needed. */
30
+ function createDatabaseHelperStub() {
31
+ return {
32
+ async runSQL(_sql, _params) {
33
+ return { rowCount: 0, rows: [] };
34
+ },
35
+ async close() { },
36
+ };
37
+ }
38
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/context/db.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAuBH,oDAoBC;AAGD,4DAOC;AA9BM,KAAK,UAAU,oBAAoB,CAAC,IAA2B;IACpE,sEAAsE;IACtE,6DAA6D;IAC7D,iEAAiE;IACjE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAwB,CAAA;IACrD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IAE7D,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,MAAkB;YAC1C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACzC,OAAO;gBACL,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,CAAC;gBAC3B,IAAI,EAAE,GAAG,CAAC,IAAiC;aAC5C,CAAA;QACH,CAAC;QAED,KAAK,CAAC,KAAK;YACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAA;QAClB,CAAC;KACF,CAAA;AACH,CAAC;AAED,qEAAqE;AACrE,SAAgB,wBAAwB;IACtC,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO;YACxB,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;QAClC,CAAC;QACD,KAAK,CAAC,KAAK,KAAI,CAAC;KACjB,CAAA;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Env var helpers — mirrors config.Env / config.EnvRequired in plugin-sdk-go.
3
+ */
4
+ /** Env helper interface exposed in PluginContext. */
5
+ export interface EnvHelper {
6
+ /**
7
+ * get returns the env var value or the default.
8
+ * Missing + no default → undefined.
9
+ */
10
+ get(key: string, defaultValue?: string): string | undefined;
11
+ /**
12
+ * require asserts that all named env vars are non-empty.
13
+ * Throws on first missing var — fail-fast at install/start time.
14
+ */
15
+ require(keys: string[]): void;
16
+ /** getInt returns the env var parsed as an integer, or the default. */
17
+ getInt(key: string, defaultValue: number): number;
18
+ /** getBool returns the env var parsed as boolean ("1"/"true"/"yes" → true). */
19
+ getBool(key: string, defaultValue: boolean): boolean;
20
+ /** getList splits the env var on commas and trims whitespace. */
21
+ getList(key: string): string[];
22
+ }
23
+ export declare function createEnvHelper(): EnvHelper;
24
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/context/env.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAE3D;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAE7B,uEAAuE;IACvE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;IAEjD,+EAA+E;IAC/E,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAA;IAEpD,iEAAiE;IACjE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC/B;AAED,wBAAgB,eAAe,IAAI,SAAS,CAuC3C"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * Env var helpers — mirrors config.Env / config.EnvRequired in plugin-sdk-go.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createEnvHelper = createEnvHelper;
7
+ function createEnvHelper() {
8
+ return {
9
+ get(key, defaultValue) {
10
+ const v = process.env[key];
11
+ if (v !== undefined && v !== '')
12
+ return v;
13
+ return defaultValue;
14
+ },
15
+ require(keys) {
16
+ for (const key of keys) {
17
+ if (!process.env[key] || process.env[key] === '') {
18
+ throw new Error(`plugin SDK: required env var ${key} is not set`);
19
+ }
20
+ }
21
+ },
22
+ getInt(key, defaultValue) {
23
+ const v = process.env[key];
24
+ if (!v)
25
+ return defaultValue;
26
+ const n = parseInt(v, 10);
27
+ return isNaN(n) ? defaultValue : n;
28
+ },
29
+ getBool(key, defaultValue) {
30
+ const v = (process.env[key] ?? '').toLowerCase();
31
+ if (['true', '1', 'yes', 'y', 'on'].includes(v))
32
+ return true;
33
+ if (['false', '0', 'no', 'n', 'off'].includes(v))
34
+ return false;
35
+ return defaultValue;
36
+ },
37
+ getList(key) {
38
+ const v = process.env[key];
39
+ if (!v)
40
+ return [];
41
+ return v
42
+ .split(',')
43
+ .map((s) => s.trim())
44
+ .filter(Boolean);
45
+ },
46
+ };
47
+ }
48
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/context/env.ts"],"names":[],"mappings":";AAAA;;GAEG;;AA0BH,0CAuCC;AAvCD,SAAgB,eAAe;IAC7B,OAAO;QACL,GAAG,CAAC,GAAW,EAAE,YAAqB;YACpC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE;gBAAE,OAAO,CAAC,CAAA;YACzC,OAAO,YAAY,CAAA;QACrB,CAAC;QAED,OAAO,CAAC,IAAc;YACpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;oBACjD,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,aAAa,CAAC,CAAA;gBACnE,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,CAAC,GAAW,EAAE,YAAoB;YACtC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,CAAC,CAAC;gBAAE,OAAO,YAAY,CAAA;YAC3B,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YACzB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;QACpC,CAAC;QAED,OAAO,CAAC,GAAW,EAAE,YAAqB;YACxC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;YAChD,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAA;YAC5D,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC9D,OAAO,YAAY,CAAA;QACrB,CAAC;QAED,OAAO,CAAC,GAAW;YACjB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,CAAC,CAAC;gBAAE,OAAO,EAAE,CAAA;YACjB,OAAO,CAAC;iBACL,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Hasura metadata API wrapper for install/migrate/uninstall hooks.
3
+ * Mirrors the HasuraHelper concept from the spec: addTable, trackRelationship,
4
+ * runMigration. Uses the Hasura Metadata API v3.
5
+ */
6
+ export interface TrackRelationshipOptions {
7
+ fromTable: string;
8
+ name: string;
9
+ type: 'object' | 'array';
10
+ toTable: string;
11
+ fromColumn: string;
12
+ toColumn: string;
13
+ }
14
+ export interface HasuraHelper {
15
+ /** Track a new table in Hasura metadata. */
16
+ addTable(schema: string, table: string): Promise<void>;
17
+ /** Untrack a table from Hasura metadata. */
18
+ removeTable(schema: string, table: string): Promise<void>;
19
+ /** Add a relationship between two tracked tables. */
20
+ trackRelationship(opts: TrackRelationshipOptions): Promise<void>;
21
+ /** Run raw Hasura metadata API request (escape hatch). */
22
+ runMetadata(type: string, args: Record<string, unknown>): Promise<unknown>;
23
+ /** Run a SQL migration via Hasura's run_sql API. */
24
+ runSql(sql: string): Promise<void>;
25
+ }
26
+ export declare function createHasuraHelper(adminSecret: string, endpoint: string): HasuraHelper;
27
+ //# sourceMappingURL=hasura.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasura.d.ts","sourceRoot":"","sources":["../../src/context/hasura.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEtD,4CAA4C;IAC5C,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzD,qDAAqD;IACrD,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEhE,0DAA0D;IAC1D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE1E,oDAAoD;IACpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnC;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAsEtF"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Hasura metadata API wrapper for install/migrate/uninstall hooks.
4
+ * Mirrors the HasuraHelper concept from the spec: addTable, trackRelationship,
5
+ * runMigration. Uses the Hasura Metadata API v3.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createHasuraHelper = createHasuraHelper;
9
+ function createHasuraHelper(adminSecret, endpoint) {
10
+ async function post(path, body) {
11
+ const url = `${endpoint}${path}`;
12
+ const res = await fetch(url, {
13
+ method: 'POST',
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ 'x-hasura-admin-secret': adminSecret,
17
+ },
18
+ body: JSON.stringify(body),
19
+ });
20
+ if (!res.ok) {
21
+ const text = await res.text();
22
+ throw new Error(`hasura: POST ${path} failed (${res.status}): ${text}`);
23
+ }
24
+ return res.json();
25
+ }
26
+ return {
27
+ async addTable(schema, table) {
28
+ await post('/v1/metadata', {
29
+ type: 'pg_track_table',
30
+ args: {
31
+ source: 'default',
32
+ schema,
33
+ name: table,
34
+ },
35
+ });
36
+ },
37
+ async removeTable(schema, table) {
38
+ await post('/v1/metadata', {
39
+ type: 'pg_untrack_table',
40
+ args: {
41
+ table: { schema, name: table },
42
+ cascade: false,
43
+ },
44
+ });
45
+ },
46
+ async trackRelationship(opts) {
47
+ const apiType = opts.type === 'object' ? 'pg_create_object_relationship' : 'pg_create_array_relationship';
48
+ await post('/v1/metadata', {
49
+ type: apiType,
50
+ args: {
51
+ source: 'default',
52
+ table: opts.fromTable,
53
+ name: opts.name,
54
+ using: {
55
+ foreign_key_constraint_on: {
56
+ table: opts.toTable,
57
+ columns: [opts.toColumn],
58
+ },
59
+ },
60
+ },
61
+ });
62
+ },
63
+ async runMetadata(type, args) {
64
+ return post('/v1/metadata', { type, args });
65
+ },
66
+ async runSql(sql) {
67
+ await post('/v2/query', {
68
+ type: 'run_sql',
69
+ args: { source: 'default', sql },
70
+ });
71
+ },
72
+ };
73
+ }
74
+ //# sourceMappingURL=hasura.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasura.js","sourceRoot":"","sources":["../../src/context/hasura.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA4BH,gDAsEC;AAtED,SAAgB,kBAAkB,CAAC,WAAmB,EAAE,QAAgB;IACtE,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,IAAa;QAC7C,MAAM,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAA;QAChC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,uBAAuB,EAAE,WAAW;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;YAC7B,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAA;QACzE,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;IACnB,CAAC;IAED,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,KAAa;YAC1C,MAAM,IAAI,CAAC,cAAc,EAAE;gBACzB,IAAI,EAAE,gBAAgB;gBACtB,IAAI,EAAE;oBACJ,MAAM,EAAE,SAAS;oBACjB,MAAM;oBACN,IAAI,EAAE,KAAK;iBACZ;aACF,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,MAAc,EAAE,KAAa;YAC7C,MAAM,IAAI,CAAC,cAAc,EAAE;gBACzB,IAAI,EAAE,kBAAkB;gBACxB,IAAI,EAAE;oBACJ,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE;oBAC9B,OAAO,EAAE,KAAK;iBACf;aACF,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,CAAC,iBAAiB,CAAC,IAA8B;YACpD,MAAM,OAAO,GACX,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,8BAA8B,CAAA;YAC3F,MAAM,IAAI,CAAC,cAAc,EAAE;gBACzB,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE;oBACJ,MAAM,EAAE,SAAS;oBACjB,KAAK,EAAE,IAAI,CAAC,SAAS;oBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE;wBACL,yBAAyB,EAAE;4BACzB,KAAK,EAAE,IAAI,CAAC,OAAO;4BACnB,OAAO,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;yBACzB;qBACF;iBACF;aACF,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,IAAY,EAAE,IAA6B;YAC3D,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7C,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,GAAW;YACtB,MAAM,IAAI,CAAC,WAAW,EAAE;gBACtB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE;aACjC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * HTTP helper: express app factory + health ping client.
3
+ * Mirrors server.New() in plugin-sdk-go: auto-mounts /healthz, /readyz,
4
+ * /version, /metrics on every plugin server.
5
+ */
6
+ import { type Express } from 'express';
7
+ import type { HealthStatus } from '../runner';
8
+ export interface HttpHelper {
9
+ /**
10
+ * createApp returns an Express application pre-configured with:
11
+ * - GET /healthz → liveness (always 200)
12
+ * - GET /readyz → delegates to the health hook
13
+ * - GET /version → plugin name + version JSON
14
+ */
15
+ createApp(): Express;
16
+ /**
17
+ * listen starts the HTTP server on the given port. Returns the net.Server
18
+ * so callers can shut it down gracefully in the uninstall hook.
19
+ */
20
+ listen(port: number): ReturnType<Express['listen']>;
21
+ /**
22
+ * ping sends GET to path on localhost:port and returns a HealthStatus.
23
+ * Used in the health hook to check this plugin's own /healthz endpoint.
24
+ */
25
+ ping(path: string): Promise<HealthStatus>;
26
+ }
27
+ export interface HttpHelperOptions {
28
+ pluginName: string;
29
+ pluginVersion: string;
30
+ port: number;
31
+ healthCheck?: () => Promise<HealthStatus>;
32
+ }
33
+ export declare function createHttpHelper(opts: HttpHelperOptions): HttpHelper;
34
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/context/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAgB,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,SAAS,IAAI,OAAO,CAAA;IAEpB;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEnD;;;OAGG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAA;CAC1C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU,CAqEpE"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * HTTP helper: express app factory + health ping client.
4
+ * Mirrors server.New() in plugin-sdk-go: auto-mounts /healthz, /readyz,
5
+ * /version, /metrics on every plugin server.
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.createHttpHelper = createHttpHelper;
12
+ const express_1 = __importDefault(require("express"));
13
+ function createHttpHelper(opts) {
14
+ let app = null;
15
+ function getOrCreateApp() {
16
+ if (app)
17
+ return app;
18
+ app = (0, express_1.default)();
19
+ app.use(express_1.default.json());
20
+ // Liveness
21
+ app.get('/healthz', (_req, res) => {
22
+ res.json({ status: 'ok', plugin: opts.pluginName, version: opts.pluginVersion });
23
+ });
24
+ // Readiness — delegates to health hook if provided
25
+ app.get('/readyz', async (_req, res) => {
26
+ if (opts.healthCheck) {
27
+ try {
28
+ const result = await opts.healthCheck();
29
+ const code = result.status === 'ok' ? 200 : 503;
30
+ res.status(code).json(result);
31
+ }
32
+ catch (err) {
33
+ const message = err instanceof Error ? err.message : String(err);
34
+ res.status(503).json({ status: 'unavailable', message });
35
+ }
36
+ }
37
+ else {
38
+ res.json({ status: 'ready' });
39
+ }
40
+ });
41
+ // Version
42
+ app.get('/version', (_req, res) => {
43
+ res.json({
44
+ plugin: opts.pluginName,
45
+ version: opts.pluginVersion,
46
+ sdk: '@nself/plugin-sdk',
47
+ });
48
+ });
49
+ return app;
50
+ }
51
+ return {
52
+ createApp() {
53
+ return getOrCreateApp();
54
+ },
55
+ listen(port) {
56
+ const application = getOrCreateApp();
57
+ return application.listen(port);
58
+ },
59
+ async ping(path) {
60
+ const url = `http://127.0.0.1:${opts.port}${path}`;
61
+ try {
62
+ const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
63
+ if (res.ok) {
64
+ return { status: 'ok' };
65
+ }
66
+ return {
67
+ status: 'degraded',
68
+ message: `GET ${path} returned HTTP ${res.status}`,
69
+ };
70
+ }
71
+ catch (err) {
72
+ const message = err instanceof Error ? err.message : String(err);
73
+ return { status: 'unavailable', message };
74
+ }
75
+ },
76
+ };
77
+ }
78
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/context/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Structured JSON logger interface and default pino implementation.
3
+ * Mirrors logger.New() in plugin-sdk-go: every record carries plugin + version.
4
+ */
5
+ /** Logger interface exposed in PluginContext — mirrors slog.Logger API shape. */
6
+ export interface Logger {
7
+ info(msg: string, attrs?: Record<string, unknown>): void;
8
+ warn(msg: string, attrs?: Record<string, unknown>): void;
9
+ error(msg: string, attrs?: Record<string, unknown>): void;
10
+ debug(msg: string, attrs?: Record<string, unknown>): void;
11
+ }
12
+ /** Factory — creates a structured JSON logger keyed to a plugin name. */
13
+ export declare function createLogger(plugin: string, version: string): Logger;
14
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/context/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iFAAiF;AACjF,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACxD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACzD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAC1D;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAoBpE"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Structured JSON logger interface and default pino implementation.
4
+ * Mirrors logger.New() in plugin-sdk-go: every record carries plugin + version.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createLogger = createLogger;
8
+ /** Factory — creates a structured JSON logger keyed to a plugin name. */
9
+ function createLogger(plugin, version) {
10
+ const base = { plugin, version };
11
+ function log(level, msg, attrs) {
12
+ const entry = {
13
+ time: new Date().toISOString(),
14
+ level,
15
+ msg,
16
+ ...base,
17
+ ...(attrs ?? {}),
18
+ };
19
+ process.stderr.write(JSON.stringify(entry) + '\n');
20
+ }
21
+ return {
22
+ info: (msg, attrs) => log('INFO', msg, attrs),
23
+ warn: (msg, attrs) => log('WARN', msg, attrs),
24
+ error: (msg, attrs) => log('ERROR', msg, attrs),
25
+ debug: (msg, attrs) => log('DEBUG', msg, attrs),
26
+ };
27
+ }
28
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/context/logger.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAWH,oCAoBC;AArBD,yEAAyE;AACzE,SAAgB,YAAY,CAAC,MAAc,EAAE,OAAe;IAC1D,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IAEzD,SAAS,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,KAA+B;QACtE,MAAM,KAAK,GAAG;YACZ,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC9B,KAAK;YACL,GAAG;YACH,GAAG,IAAI;YACP,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;SACjB,CAAA;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAA;IACpD,CAAC;IAED,OAAO;QACL,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;QAC7C,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;QAC7C,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;QAC/C,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;KAChD,CAAA;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Nginx route injection helper.
3
+ * nSelf generates nginx/conf.d/<plugin>.conf at build time; this helper
4
+ * provides the typed interface for plugins to declare their routes.
5
+ * At runtime the CLI reads plugin.yaml for routes — this helper is used
6
+ * during install hooks to validate / extend the manifest-declared routes.
7
+ */
8
+ export interface RouteOptions {
9
+ /** Location path, e.g. "/notify/" */
10
+ location: string;
11
+ /** Upstream host:port, e.g. "127.0.0.1:3830" */
12
+ upstream: string;
13
+ /** Extra nginx directives injected inside the location block. */
14
+ extraDirectives?: string[];
15
+ }
16
+ export interface NginxHelper {
17
+ /** Register a proxy_pass route to the plugin's upstream. */
18
+ addRoute(opts: RouteOptions): void;
19
+ /** Remove a previously registered route (used in uninstall). */
20
+ removeRoute(location: string): void;
21
+ /** Returns all routes registered in this session. */
22
+ getRoutes(): RouteOptions[];
23
+ }
24
+ export declare function createNginxHelper(): NginxHelper;
25
+ //# sourceMappingURL=nginx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/context/nginx.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAA;IAElC,gEAAgE;IAChE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAEnC,qDAAqD;IACrD,SAAS,IAAI,YAAY,EAAE,CAAA;CAC5B;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAoB/C"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * Nginx route injection helper.
4
+ * nSelf generates nginx/conf.d/<plugin>.conf at build time; this helper
5
+ * provides the typed interface for plugins to declare their routes.
6
+ * At runtime the CLI reads plugin.yaml for routes — this helper is used
7
+ * during install hooks to validate / extend the manifest-declared routes.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.createNginxHelper = createNginxHelper;
11
+ function createNginxHelper() {
12
+ const routes = [];
13
+ return {
14
+ addRoute(opts) {
15
+ if (!opts.location.startsWith('/')) {
16
+ throw new Error(`nginx: location must start with "/", got "${opts.location}"`);
17
+ }
18
+ routes.push(opts);
19
+ },
20
+ removeRoute(location) {
21
+ const idx = routes.findIndex((r) => r.location === location);
22
+ if (idx !== -1)
23
+ routes.splice(idx, 1);
24
+ },
25
+ getRoutes() {
26
+ return [...routes];
27
+ },
28
+ };
29
+ }
30
+ //# sourceMappingURL=nginx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.js","sourceRoot":"","sources":["../../src/context/nginx.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAsBH,8CAoBC;AApBD,SAAgB,iBAAiB;IAC/B,MAAM,MAAM,GAAmB,EAAE,CAAA;IAEjC,OAAO;QACL,QAAQ,CAAC,IAAkB;YACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;YAChF,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnB,CAAC;QAED,WAAW,CAAC,QAAgB;YAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAA;YAC5D,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACvC,CAAC;QAED,SAAS;YACP,OAAO,CAAC,GAAG,MAAM,CAAC,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @nself/plugin-sdk — TypeScript plugin authoring SDK for nSelf.
3
+ *
4
+ * Mirror of plugin-sdk-go v0.1.0: lifecycle hooks (install, start, health,
5
+ * migrate, uninstall), PluginContext with env/hasura/nginx/db/http/logger
6
+ * helpers, and a plugin.yaml manifest parser.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { definePlugin, type PluginContext } from '@nself/plugin-sdk'
11
+ *
12
+ * export default definePlugin({
13
+ * name: 'my-notify',
14
+ * version: '1.0.0',
15
+ *
16
+ * async install(ctx: PluginContext) {
17
+ * await ctx.env.require(['SMTP_HOST', 'SMTP_PORT'])
18
+ * },
19
+ *
20
+ * async start(ctx: PluginContext) {
21
+ * const app = ctx.http.createApp()
22
+ * app.get('/notify/healthz', (_req, res) => res.json({ status: 'ok' }))
23
+ * ctx.http.listen(ctx.port)
24
+ * },
25
+ *
26
+ * async health(ctx: PluginContext) {
27
+ * return ctx.http.ping('/notify/healthz')
28
+ * },
29
+ * })
30
+ * ```
31
+ */
32
+ export { definePlugin } from './runner';
33
+ export type { PluginDefinition, PluginContext, HealthStatus, PluginInfo, } from './runner';
34
+ export type { EnvHelper } from './context/env';
35
+ export type { HasuraHelper } from './context/hasura';
36
+ export type { NginxHelper } from './context/nginx';
37
+ export type { DatabaseHelper } from './context/db';
38
+ export type { HttpHelper } from './context/http';
39
+ export type { Logger } from './context/logger';
40
+ export { parseManifest, type PluginManifest } from './manifest/parser';
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,YAAY,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * @nself/plugin-sdk — TypeScript plugin authoring SDK for nSelf.
4
+ *
5
+ * Mirror of plugin-sdk-go v0.1.0: lifecycle hooks (install, start, health,
6
+ * migrate, uninstall), PluginContext with env/hasura/nginx/db/http/logger
7
+ * helpers, and a plugin.yaml manifest parser.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { definePlugin, type PluginContext } from '@nself/plugin-sdk'
12
+ *
13
+ * export default definePlugin({
14
+ * name: 'my-notify',
15
+ * version: '1.0.0',
16
+ *
17
+ * async install(ctx: PluginContext) {
18
+ * await ctx.env.require(['SMTP_HOST', 'SMTP_PORT'])
19
+ * },
20
+ *
21
+ * async start(ctx: PluginContext) {
22
+ * const app = ctx.http.createApp()
23
+ * app.get('/notify/healthz', (_req, res) => res.json({ status: 'ok' }))
24
+ * ctx.http.listen(ctx.port)
25
+ * },
26
+ *
27
+ * async health(ctx: PluginContext) {
28
+ * return ctx.http.ping('/notify/healthz')
29
+ * },
30
+ * })
31
+ * ```
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.parseManifest = exports.definePlugin = void 0;
35
+ var runner_1 = require("./runner");
36
+ Object.defineProperty(exports, "definePlugin", { enumerable: true, get: function () { return runner_1.definePlugin; } });
37
+ var parser_1 = require("./manifest/parser");
38
+ Object.defineProperty(exports, "parseManifest", { enumerable: true, get: function () { return parser_1.parseManifest; } });
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;;AAEH,mCAAuC;AAA9B,sGAAA,YAAY,OAAA;AAarB,4CAAsE;AAA7D,uGAAA,aAAa,OAAA"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * plugin.yaml manifest parser and validator.
3
+ * The manifest is the schema the nSelf CLI reads to register a plugin.
4
+ * Mirrors the manifest parser in plugin-sdk-go (config/config.go + plugin.Info).
5
+ */
6
+ /** Full plugin manifest shape as declared in plugin.yaml. */
7
+ export interface PluginManifest {
8
+ name: string;
9
+ version: string;
10
+ description?: string;
11
+ tier: 'free' | 'pro';
12
+ bundle?: string;
13
+ minCli?: string;
14
+ minSdk?: string;
15
+ port?: number;
16
+ /** Hasura GraphQL routes provided by this plugin. */
17
+ routes?: Array<{
18
+ path: string;
19
+ upstream: string;
20
+ }>;
21
+ /** Env vars required at install time. */
22
+ requiredEnv?: string[];
23
+ /** Free-form metadata extension slot. */
24
+ metadata?: Record<string, string>;
25
+ }
26
+ /** Validation error returned when the manifest is malformed. */
27
+ export declare class ManifestValidationError extends Error {
28
+ readonly field?: string | undefined;
29
+ constructor(message: string, field?: string | undefined);
30
+ }
31
+ /**
32
+ * parseManifest reads and validates a plugin.yaml file.
33
+ * Throws ManifestValidationError on missing required fields.
34
+ *
35
+ * @param filePath - path to plugin.yaml (defaults to ./plugin.yaml)
36
+ */
37
+ export declare function parseManifest(filePath?: string): PluginManifest;
38
+ /**
39
+ * parseManifestFromString parses plugin.yaml content from a string.
40
+ * Useful in tests.
41
+ */
42
+ export declare function parseManifestFromString(content: string): PluginManifest;
43
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/manifest/parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,qDAAqD;IACrD,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAC,CAAA;IAEF,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IAEtB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,gEAAgE;AAChE,qBAAa,uBAAwB,SAAQ,KAAK;aAG9B,KAAK,CAAC,EAAE,MAAM;gBAD9B,OAAO,EAAE,MAAM,EACC,KAAK,CAAC,EAAE,MAAM,YAAA;CAKjC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,CAkB/D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CASvE"}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * plugin.yaml manifest parser and validator.
4
+ * The manifest is the schema the nSelf CLI reads to register a plugin.
5
+ * Mirrors the manifest parser in plugin-sdk-go (config/config.go + plugin.Info).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ManifestValidationError = void 0;
9
+ exports.parseManifest = parseManifest;
10
+ exports.parseManifestFromString = parseManifestFromString;
11
+ const yaml_1 = require("yaml");
12
+ const fs_1 = require("fs");
13
+ const path_1 = require("path");
14
+ /** Validation error returned when the manifest is malformed. */
15
+ class ManifestValidationError extends Error {
16
+ constructor(message, field) {
17
+ super(`plugin manifest: ${message}`);
18
+ this.field = field;
19
+ this.name = 'ManifestValidationError';
20
+ }
21
+ }
22
+ exports.ManifestValidationError = ManifestValidationError;
23
+ /**
24
+ * parseManifest reads and validates a plugin.yaml file.
25
+ * Throws ManifestValidationError on missing required fields.
26
+ *
27
+ * @param filePath - path to plugin.yaml (defaults to ./plugin.yaml)
28
+ */
29
+ function parseManifest(filePath) {
30
+ const resolvedPath = (0, path_1.resolve)(filePath ?? 'plugin.yaml');
31
+ let raw;
32
+ try {
33
+ raw = (0, fs_1.readFileSync)(resolvedPath, 'utf-8');
34
+ }
35
+ catch {
36
+ throw new ManifestValidationError(`cannot read file: ${resolvedPath}`);
37
+ }
38
+ let parsed;
39
+ try {
40
+ parsed = (0, yaml_1.parse)(raw);
41
+ }
42
+ catch (err) {
43
+ const msg = err instanceof Error ? err.message : String(err);
44
+ throw new ManifestValidationError(`YAML parse error: ${msg}`);
45
+ }
46
+ return validateManifest(parsed);
47
+ }
48
+ /**
49
+ * parseManifestFromString parses plugin.yaml content from a string.
50
+ * Useful in tests.
51
+ */
52
+ function parseManifestFromString(content) {
53
+ let parsed;
54
+ try {
55
+ parsed = (0, yaml_1.parse)(content);
56
+ }
57
+ catch (err) {
58
+ const msg = err instanceof Error ? err.message : String(err);
59
+ throw new ManifestValidationError(`YAML parse error: ${msg}`);
60
+ }
61
+ return validateManifest(parsed);
62
+ }
63
+ function validateManifest(raw) {
64
+ if (typeof raw !== 'object' || raw === null) {
65
+ throw new ManifestValidationError('manifest must be a YAML object');
66
+ }
67
+ const m = raw;
68
+ if (!m['name'] || typeof m['name'] !== 'string') {
69
+ throw new ManifestValidationError('name is required and must be a string', 'name');
70
+ }
71
+ if (!m['version'] || typeof m['version'] !== 'string') {
72
+ throw new ManifestValidationError('version is required and must be a string', 'version');
73
+ }
74
+ if (m['tier'] !== 'free' && m['tier'] !== 'pro') {
75
+ throw new ManifestValidationError('tier must be "free" or "pro"', 'tier');
76
+ }
77
+ return m;
78
+ }
79
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/manifest/parser.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AA+CH,sCAkBC;AAMD,0DASC;AA9ED,+BAA4B;AAC5B,2BAAiC;AACjC,+BAA8B;AA0B9B,gEAAgE;AAChE,MAAa,uBAAwB,SAAQ,KAAK;IAChD,YACE,OAAe,EACC,KAAc;QAE9B,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAA;QAFpB,UAAK,GAAL,KAAK,CAAS;QAG9B,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAA;IACvC,CAAC;CACF;AARD,0DAQC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,QAAiB;IAC7C,MAAM,YAAY,GAAG,IAAA,cAAO,EAAC,QAAQ,IAAI,aAAa,CAAC,CAAA;IACvD,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,IAAA,iBAAY,EAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,uBAAuB,CAAC,qBAAqB,YAAY,EAAE,CAAC,CAAA;IACxE,CAAC;IAED,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAA,YAAK,EAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5D,MAAM,IAAI,uBAAuB,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAA;IAC/D,CAAC;IAED,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAA;AACjC,CAAC;AAED;;;GAGG;AACH,SAAgB,uBAAuB,CAAC,OAAe;IACrD,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAA,YAAK,EAAC,OAAO,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5D,MAAM,IAAI,uBAAuB,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAA;AACjC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAY;IACpC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,uBAAuB,CAAC,gCAAgC,CAAC,CAAA;IACrE,CAAC;IAED,MAAM,CAAC,GAAG,GAA8B,CAAA;IAExC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,uBAAuB,CAAC,uCAAuC,EAAE,MAAM,CAAC,CAAA;IACpF,CAAC;IACD,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,IAAI,uBAAuB,CAAC,0CAA0C,EAAE,SAAS,CAAC,CAAA;IAC1F,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC;QAChD,MAAM,IAAI,uBAAuB,CAAC,8BAA8B,EAAE,MAAM,CAAC,CAAA;IAC3E,CAAC;IAED,OAAO,CAA8B,CAAA;AACvC,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Lifecycle orchestrator: defines PluginDefinition, PluginContext, and the
3
+ * definePlugin() factory. Mirrors the plugin.Plugin interface in plugin-sdk-go.
4
+ */
5
+ import type { EnvHelper } from './context/env';
6
+ import type { HasuraHelper } from './context/hasura';
7
+ import type { NginxHelper } from './context/nginx';
8
+ import type { DatabaseHelper } from './context/db';
9
+ import type { HttpHelper } from './context/http';
10
+ import type { Logger } from './context/logger';
11
+ /** Identity metadata for a plugin — mirrors plugin-sdk-go plugin.Info. */
12
+ export interface PluginInfo {
13
+ name: string;
14
+ version: string;
15
+ description?: string;
16
+ tier?: 'free' | 'pro';
17
+ bundle?: string;
18
+ minCli?: string;
19
+ minSdk?: string;
20
+ }
21
+ /** Health check result returned by the health hook. */
22
+ export interface HealthStatus {
23
+ status: 'ok' | 'degraded' | 'unavailable';
24
+ message?: string;
25
+ checks?: Record<string, boolean>;
26
+ }
27
+ /**
28
+ * Runtime context passed to every lifecycle hook.
29
+ * Mirrors the PluginContext struct in the spec and the helpers in plugin-sdk-go.
30
+ */
31
+ export interface PluginContext {
32
+ /** TCP port the plugin should bind to (from NSELF_PLUGIN_PORT env var). */
33
+ port: number;
34
+ /** Structured JSON logger keyed to the plugin name. */
35
+ logger: Logger;
36
+ /** Env var helpers: require(), get(), getInt(), getBool(). */
37
+ env: EnvHelper;
38
+ /** Hasura metadata API wrapper. */
39
+ hasura: HasuraHelper;
40
+ /** Nginx route injection helper. */
41
+ nginx: NginxHelper;
42
+ /**
43
+ * PostgreSQL helper for migration-time DDL only.
44
+ * Not for query-time use — plugins talk to Hasura GraphQL.
45
+ */
46
+ db: DatabaseHelper;
47
+ /** Express app factory + health ping client. */
48
+ http: HttpHelper;
49
+ }
50
+ /**
51
+ * The shape a plugin author fills in with definePlugin().
52
+ * All hooks are optional except name + version.
53
+ */
54
+ export interface PluginDefinition {
55
+ /** Plugin name — must match the plugin.yaml `name` field. */
56
+ name: string;
57
+ /** SemVer string, e.g. "1.0.0". */
58
+ version: string;
59
+ /** Short human description. */
60
+ description?: string;
61
+ /** Tier reported in /version endpoint. */
62
+ tier?: 'free' | 'pro';
63
+ /** Bundle this plugin belongs to, e.g. "nClaw". */
64
+ bundle?: string;
65
+ /**
66
+ * install — runs on `nself plugin install`.
67
+ * Use to apply Hasura metadata, verify env vars, and register Nginx routes.
68
+ */
69
+ install?: (ctx: PluginContext) => Promise<void>;
70
+ /**
71
+ * start — runs when `nself start` brings the plugin container up.
72
+ * Should create an HTTP app and call ctx.http.listen(ctx.port).
73
+ */
74
+ start?: (ctx: PluginContext) => Promise<void>;
75
+ /**
76
+ * health — polled by `nself doctor`. Return status 'ok' when fully ready.
77
+ * The runner builds a /healthz endpoint automatically; health() is used for
78
+ * deeper readiness checks surfaced via /readyz.
79
+ */
80
+ health?: (ctx: PluginContext) => Promise<HealthStatus>;
81
+ /**
82
+ * migrate — runs Hasura metadata + SQL migrations during `nself start` before
83
+ * the plugin begins serving traffic.
84
+ */
85
+ migrate?: (ctx: PluginContext) => Promise<void>;
86
+ /**
87
+ * uninstall — runs on `nself plugin remove`.
88
+ * Clean up Hasura metadata and Nginx routes; preserve user data by default.
89
+ */
90
+ uninstall?: (ctx: PluginContext) => Promise<void>;
91
+ }
92
+ /**
93
+ * definePlugin registers a plugin definition and returns it for use by the
94
+ * nSelf CLI runner. Acts as the primary authoring entry point.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * export default definePlugin({
99
+ * name: 'notify',
100
+ * version: '1.0.0',
101
+ * async start(ctx) {
102
+ * const app = ctx.http.createApp()
103
+ * app.post('/notify/send', myHandler)
104
+ * ctx.http.listen(ctx.port)
105
+ * },
106
+ * })
107
+ * ```
108
+ */
109
+ export declare function definePlugin(definition: PluginDefinition): PluginDefinition;
110
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAE9C,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,IAAI,GAAG,UAAU,GAAG,aAAa,CAAA;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,GAAG,EAAE,SAAS,CAAA;IACd,mCAAmC;IACnC,MAAM,EAAE,YAAY,CAAA;IACpB,oCAAoC;IACpC,KAAK,EAAE,WAAW,CAAA;IAClB;;;OAGG;IACH,EAAE,EAAE,cAAc,CAAA;IAClB,gDAAgD;IAChD,IAAI,EAAE,UAAU,CAAA;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IACZ,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE/C;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7C;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IAEtD;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE/C;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,gBAAgB,GAAG,gBAAgB,CAI3E"}
package/dist/runner.js ADDED
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /**
3
+ * Lifecycle orchestrator: defines PluginDefinition, PluginContext, and the
4
+ * definePlugin() factory. Mirrors the plugin.Plugin interface in plugin-sdk-go.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.definePlugin = definePlugin;
8
+ /**
9
+ * definePlugin registers a plugin definition and returns it for use by the
10
+ * nSelf CLI runner. Acts as the primary authoring entry point.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * export default definePlugin({
15
+ * name: 'notify',
16
+ * version: '1.0.0',
17
+ * async start(ctx) {
18
+ * const app = ctx.http.createApp()
19
+ * app.post('/notify/send', myHandler)
20
+ * ctx.http.listen(ctx.port)
21
+ * },
22
+ * })
23
+ * ```
24
+ */
25
+ function definePlugin(definition) {
26
+ if (!definition.name)
27
+ throw new Error('plugin SDK: name is required');
28
+ if (!definition.version)
29
+ throw new Error('plugin SDK: version is required');
30
+ return definition;
31
+ }
32
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAoHH,oCAIC;AArBD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,YAAY,CAAC,UAA4B;IACvD,IAAI,CAAC,UAAU,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IACrE,IAAI,CAAC,UAAU,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IAC3E,OAAO,UAAU,CAAA;AACnB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@nself/plugin-sdk",
3
+ "version": "1.2.4",
4
+ "description": "TypeScript/Node.js plugin authoring SDK for nSelf",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "templates"
16
+ ],
17
+ "dependencies": {
18
+ "express": "^4.18.3",
19
+ "pino": "^9.1.0",
20
+ "yaml": "^2.4.1"
21
+ },
22
+ "peerDependencies": {
23
+ "pg": "^8.11.0"
24
+ },
25
+ "peerDependenciesMeta": {
26
+ "pg": {
27
+ "optional": true
28
+ }
29
+ },
30
+ "devDependencies": {
31
+ "@types/express": "^4.17.21",
32
+ "@types/jest": "^29.5.12",
33
+ "@types/node": "^25.8.0",
34
+ "@types/pg": "^8.11.0",
35
+ "@typescript-eslint/eslint-plugin": "^8.59.3",
36
+ "@typescript-eslint/parser": "^8.59.3",
37
+ "eslint": "^10.4.0",
38
+ "jest": "^29.7.0",
39
+ "ts-jest": "^29.1.2",
40
+ "typescript": "^6.0.3"
41
+ },
42
+ "jest": {
43
+ "testEnvironment": "node",
44
+ "testMatch": [
45
+ "**/*.test.ts"
46
+ ],
47
+ "transform": {
48
+ "^.+\\.ts$": [
49
+ "ts-jest",
50
+ {
51
+ "tsconfig": "tsconfig.test.json"
52
+ }
53
+ ]
54
+ }
55
+ },
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "https://github.com/nself-org/cli.git",
59
+ "directory": "sdk/ts"
60
+ },
61
+ "license": "MIT",
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "scripts": {
66
+ "build": "tsc",
67
+ "test": "jest",
68
+ "typecheck": "tsc --noEmit",
69
+ "lint": "eslint src test"
70
+ }
71
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "my-plugin",
3
+ "version": "1.0.0",
4
+ "description": "My nSelf plugin",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "start": "node dist/index.js",
9
+ "dev": "ts-node src/index.ts"
10
+ },
11
+ "dependencies": {
12
+ "@nself/plugin-sdk": "^0.1.0"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^20.0.0",
16
+ "typescript": "^6.0.3"
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ name: my-plugin
2
+ version: 1.0.0
3
+ description: My nSelf plugin built with @nself/plugin-sdk
4
+ tier: free
5
+ port: 3850
6
+
7
+ # Required environment variables (checked at install time)
8
+ requiredEnv: []
9
+
10
+ # Nginx routes this plugin exposes (populated by the CLI at build time)
11
+ routes: []
@@ -0,0 +1,42 @@
1
+ import { definePlugin, type PluginContext, type HealthStatus } from '@nself/plugin-sdk'
2
+
3
+ export default definePlugin({
4
+ name: 'my-plugin',
5
+ version: '1.0.0',
6
+
7
+ async install(ctx: PluginContext): Promise<void> {
8
+ ctx.logger.info('installing my-plugin')
9
+ // Verify required env vars
10
+ ctx.env.require([])
11
+ // Register Nginx route
12
+ ctx.nginx.addRoute({
13
+ location: '/my-plugin/',
14
+ upstream: `127.0.0.1:${ctx.port}`,
15
+ })
16
+ },
17
+
18
+ async start(ctx: PluginContext): Promise<void> {
19
+ ctx.logger.info('starting my-plugin', { port: ctx.port })
20
+ const app = ctx.http.createApp()
21
+
22
+ // Add your routes here
23
+ app.get('/my-plugin/hello', (_req, res) => {
24
+ res.json({ message: 'Hello from my-plugin!' })
25
+ })
26
+
27
+ ctx.http.listen(ctx.port)
28
+ },
29
+
30
+ async health(ctx: PluginContext): Promise<HealthStatus> {
31
+ return ctx.http.ping('/my-plugin/healthz')
32
+ },
33
+
34
+ async migrate(_ctx: PluginContext): Promise<void> {
35
+ // Run Hasura metadata or SQL migrations here
36
+ },
37
+
38
+ async uninstall(ctx: PluginContext): Promise<void> {
39
+ ctx.logger.info('uninstalling my-plugin')
40
+ ctx.nginx.removeRoute('/my-plugin/')
41
+ },
42
+ })