nextpluggable 0.0.0-stage → 0.1.1

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 (77) hide show
  1. package/README.md +288 -2
  2. package/bin/nextpluggable.js +10 -0
  3. package/dist/api/handler.d.ts +10 -0
  4. package/dist/api/handler.js +188 -0
  5. package/dist/auth/custom.d.ts +13 -0
  6. package/dist/auth/custom.js +12 -0
  7. package/dist/auth/password.d.ts +10 -0
  8. package/dist/auth/password.js +66 -0
  9. package/dist/auth/types.d.ts +23 -0
  10. package/dist/auth/types.js +1 -0
  11. package/dist/cli.d.ts +9 -0
  12. package/dist/cli.js +123 -0
  13. package/dist/client/host-runtime.d.ts +9 -0
  14. package/dist/client/host-runtime.js +71 -0
  15. package/dist/client/island.d.ts +28 -0
  16. package/dist/client/island.js +177 -0
  17. package/dist/client/ssr-guard.d.ts +11 -0
  18. package/dist/client/ssr-guard.js +100 -0
  19. package/dist/config.d.ts +55 -0
  20. package/dist/config.js +57 -0
  21. package/dist/core/installer.d.ts +30 -0
  22. package/dist/core/installer.js +340 -0
  23. package/dist/core/routes.d.ts +20 -0
  24. package/dist/core/routes.js +95 -0
  25. package/dist/core/runtime.d.ts +34 -0
  26. package/dist/core/runtime.js +195 -0
  27. package/dist/core/sitemap.d.ts +12 -0
  28. package/dist/core/sitemap.js +83 -0
  29. package/dist/core/state.d.ts +13 -0
  30. package/dist/core/state.js +23 -0
  31. package/dist/core/store.d.ts +17 -0
  32. package/dist/core/store.js +58 -0
  33. package/dist/core/types.d.ts +69 -0
  34. package/dist/core/types.js +1 -0
  35. package/dist/crypto.d.ts +14 -0
  36. package/dist/crypto.js +61 -0
  37. package/dist/dashboard/Dashboard.d.ts +11 -0
  38. package/dist/dashboard/Dashboard.js +324 -0
  39. package/dist/dashboard/styles.d.ts +2 -0
  40. package/dist/dashboard/styles.js +129 -0
  41. package/dist/dashboard/ui.d.ts +61 -0
  42. package/dist/dashboard/ui.js +135 -0
  43. package/dist/errors.d.ts +15 -0
  44. package/dist/errors.js +29 -0
  45. package/dist/globals.d.ts +24 -0
  46. package/dist/globals.js +24 -0
  47. package/dist/index.d.ts +47 -0
  48. package/dist/index.js +65 -0
  49. package/dist/next/dashboard-page.d.ts +5 -0
  50. package/dist/next/dashboard-page.js +23 -0
  51. package/dist/next/plugin-page.d.ts +16 -0
  52. package/dist/next/plugin-page.js +91 -0
  53. package/dist/next/seo.d.ts +32 -0
  54. package/dist/next/seo.js +86 -0
  55. package/dist/next/slot.d.ts +7 -0
  56. package/dist/next/slot.js +43 -0
  57. package/dist/next/style.d.ts +10 -0
  58. package/dist/next/style.js +13 -0
  59. package/dist/sources/github.d.ts +19 -0
  60. package/dist/sources/github.js +109 -0
  61. package/dist/sources/local.d.ts +3 -0
  62. package/dist/sources/local.js +22 -0
  63. package/dist/sources/reader.d.ts +17 -0
  64. package/dist/sources/reader.js +78 -0
  65. package/dist/storage/file.d.ts +12 -0
  66. package/dist/storage/file.js +61 -0
  67. package/dist/storage/memory.d.ts +3 -0
  68. package/dist/storage/memory.js +22 -0
  69. package/dist/storage/postgres.d.ts +15 -0
  70. package/dist/storage/postgres.js +39 -0
  71. package/dist/storage/types.d.ts +18 -0
  72. package/dist/storage/types.js +15 -0
  73. package/dist/storage/upstash.d.ts +15 -0
  74. package/dist/storage/upstash.js +61 -0
  75. package/dist/views.d.ts +112 -0
  76. package/dist/views.js +124 -0
  77. package/package.json +48 -3
@@ -0,0 +1,112 @@
1
+ import type { SettingField } from '@nextpluggable/plugin/manifest';
2
+ import type { AdminUser } from './auth/types.js';
3
+ import type { ResolvedConfig } from './config.js';
4
+ export interface SessionView {
5
+ user: AdminUser | null;
6
+ mode: 'password' | 'custom';
7
+ /** False when no password/secret has been set up yet. */
8
+ configured: boolean;
9
+ loginUrl?: string;
10
+ }
11
+ export interface PageView {
12
+ id: string;
13
+ title: string;
14
+ description?: string;
15
+ path: string;
16
+ defaultPath: string;
17
+ /** Whether the owner may change the address. */
18
+ configurable: boolean;
19
+ /** False for pattern pages such as /shop/:slug, which cannot be opened directly. */
20
+ linkable: boolean;
21
+ }
22
+ export interface PluginView {
23
+ id: string;
24
+ name: string;
25
+ version: string;
26
+ description?: string;
27
+ author?: string;
28
+ icon?: string;
29
+ category?: string;
30
+ enabled: boolean;
31
+ needsSetup: boolean;
32
+ pages: PageView[];
33
+ slots: string[];
34
+ adminPages: {
35
+ id: string;
36
+ title: string;
37
+ component: string;
38
+ }[];
39
+ settings: SettingField[];
40
+ /** Current values of non-secret settings. */
41
+ values: Record<string, string | number | boolean>;
42
+ /** Which secret settings have a stored value. */
43
+ secretsSet: Record<string, boolean>;
44
+ permissions: string[];
45
+ hasServer: boolean;
46
+ source: {
47
+ id: string;
48
+ label: string;
49
+ connected: boolean;
50
+ };
51
+ update: {
52
+ version: string;
53
+ } | null;
54
+ installedAt: string;
55
+ updatedAt: string;
56
+ /** What the dashboard needs to render the plugin's own admin screens. */
57
+ runtime: {
58
+ moduleKey: string;
59
+ scriptSrc: string;
60
+ styleHref?: string;
61
+ apiBase: string;
62
+ publicConfig: Record<string, unknown>;
63
+ paths: Record<string, string>;
64
+ } | null;
65
+ }
66
+ export interface CatalogPluginView {
67
+ sourceId: string;
68
+ sourceLabel: string;
69
+ path: string;
70
+ id: string;
71
+ name: string;
72
+ version: string;
73
+ description?: string;
74
+ author?: string;
75
+ icon?: string;
76
+ category?: string;
77
+ pages: {
78
+ title: string;
79
+ path: string;
80
+ }[];
81
+ slots: string[];
82
+ adminPages: string[];
83
+ permissions: string[];
84
+ hasServer: boolean;
85
+ installed: boolean;
86
+ }
87
+ export interface SourceView {
88
+ id: string;
89
+ type: 'github' | 'local';
90
+ label: string;
91
+ url?: string;
92
+ hasToken: boolean;
93
+ addedAt: string;
94
+ checkedAt?: string;
95
+ name?: string;
96
+ pluginCount: number;
97
+ problems: {
98
+ path: string;
99
+ message: string;
100
+ }[];
101
+ }
102
+ export interface DashboardState {
103
+ plugins: PluginView[];
104
+ catalog: CatalogPluginView[];
105
+ sources: SourceView[];
106
+ site: {
107
+ name: string;
108
+ url: string;
109
+ allowLocalSources: boolean;
110
+ };
111
+ }
112
+ export declare function buildDashboardState(cfg: ResolvedConfig): Promise<DashboardState>;
package/dist/views.js ADDED
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The shapes the dashboard UI receives. Built on the server so that nothing
3
+ * sensitive (tokens, secrets, server-only settings' internals) reaches the browser by accident.
4
+ */
5
+ import { isStaticPath } from '@nextpluggable/plugin/manifest';
6
+ import { isEncrypted } from './crypto.js';
7
+ import { needsSetup } from './core/installer.js';
8
+ import { effectivePaths } from './core/routes.js';
9
+ import { assetUrl, clientModuleKey, publicConfig } from './core/runtime.js';
10
+ import { getCatalog, getInstalls, getSources } from './core/store.js';
11
+ function pluginView(cfg, install, catalogs, connected) {
12
+ const m = install.manifest;
13
+ const paths = effectivePaths(install);
14
+ const values = {};
15
+ const secretsSet = {};
16
+ for (const f of m.settings ?? []) {
17
+ const v = install.config[f.key];
18
+ if (f.type === 'secret')
19
+ secretsSet[f.key] = isEncrypted(v);
20
+ else if (v !== undefined)
21
+ values[f.key] = v;
22
+ }
23
+ const offered = catalogs.get(install.source.id)?.plugins.find((p) => p.build.manifest.id === install.id);
24
+ const moduleKey = clientModuleKey(install);
25
+ return {
26
+ id: install.id,
27
+ name: m.name,
28
+ version: m.version,
29
+ description: m.description,
30
+ author: m.author,
31
+ icon: install.icon,
32
+ category: m.category,
33
+ enabled: install.enabled,
34
+ needsSetup: needsSetup(m, install.config),
35
+ pages: (m.pages ?? []).map((p) => ({
36
+ id: p.id,
37
+ title: p.title,
38
+ description: p.description,
39
+ path: paths[p.id],
40
+ defaultPath: p.path,
41
+ configurable: p.configurablePath !== false && isStaticPath(p.path),
42
+ linkable: isStaticPath(paths[p.id]),
43
+ })),
44
+ slots: [...new Set((m.slots ?? []).map((s) => s.slot))],
45
+ adminPages: (m.admin ?? []).map((a) => ({ id: a.id, title: a.title, component: a.component })),
46
+ settings: m.settings ?? [],
47
+ values,
48
+ secretsSet,
49
+ permissions: m.permissions ?? [],
50
+ hasServer: Boolean(install.files.server),
51
+ source: { id: install.source.id, label: install.source.label, connected: connected.has(install.source.id) },
52
+ update: offered && offered.buildHash !== install.buildHash ? { version: offered.build.manifest.version } : null,
53
+ installedAt: install.installedAt,
54
+ updatedAt: install.updatedAt,
55
+ runtime: moduleKey && install.files.client
56
+ ? {
57
+ moduleKey,
58
+ scriptSrc: assetUrl(cfg, install.id, install.files.client.sha256, 'client.js'),
59
+ styleHref: install.files.style ? assetUrl(cfg, install.id, install.files.style.sha256, 'style.css') : undefined,
60
+ apiBase: `${cfg.apiPath}/p/${install.id}`,
61
+ publicConfig: publicConfig(install),
62
+ paths,
63
+ }
64
+ : null,
65
+ };
66
+ }
67
+ export async function buildDashboardState(cfg) {
68
+ const [sources, installs] = await Promise.all([getSources(cfg.storage), getInstalls(cfg.storage)]);
69
+ const catalogs = new Map();
70
+ await Promise.all(sources.map(async (s) => {
71
+ const c = await getCatalog(cfg.storage, s.id);
72
+ if (c)
73
+ catalogs.set(s.id, c);
74
+ }));
75
+ const connected = new Set(sources.map((s) => s.id));
76
+ const byName = (a, b) => a.name.localeCompare(b.name);
77
+ const catalog = [];
78
+ for (const s of sources)
79
+ for (const entry of catalogs.get(s.id)?.plugins ?? []) {
80
+ const m = entry.build.manifest;
81
+ catalog.push({
82
+ sourceId: s.id,
83
+ sourceLabel: s.label,
84
+ path: entry.path,
85
+ id: m.id,
86
+ name: m.name,
87
+ version: m.version,
88
+ description: m.description,
89
+ author: m.author,
90
+ icon: entry.build.icon,
91
+ category: m.category,
92
+ pages: (m.pages ?? []).map((p) => ({ title: p.title, path: p.path })),
93
+ slots: [...new Set((m.slots ?? []).map((x) => x.slot))],
94
+ adminPages: (m.admin ?? []).map((a) => a.title),
95
+ permissions: m.permissions ?? [],
96
+ hasServer: Boolean(entry.build.files.server),
97
+ installed: Boolean(installs[m.id]),
98
+ });
99
+ }
100
+ return {
101
+ plugins: Object.values(installs)
102
+ .map((i) => pluginView(cfg, i, catalogs, connected))
103
+ .sort(byName),
104
+ catalog: catalog.sort(byName),
105
+ sources: sources.map((s) => {
106
+ const c = catalogs.get(s.id);
107
+ return {
108
+ id: s.id,
109
+ type: s.type,
110
+ label: s.label,
111
+ url: s.github
112
+ ? `https://github.com/${s.github.owner}/${s.github.repo}${s.github.dir || s.github.ref ? `/tree/${s.github.ref ?? 'HEAD'}${s.github.dir ? `/${s.github.dir}` : ''}` : ''}`
113
+ : undefined,
114
+ hasToken: Boolean(s.github?.token),
115
+ addedAt: s.addedAt,
116
+ checkedAt: c?.fetchedAt,
117
+ name: c?.name,
118
+ pluginCount: c?.plugins.length ?? 0,
119
+ problems: c?.problems ?? [],
120
+ };
121
+ }),
122
+ site: { name: cfg.siteName, url: cfg.siteUrl, allowLocalSources: cfg.allowLocalSources },
123
+ };
124
+ }
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "nextpluggable",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "description": "WordPress-style plugins for Next.js: a dashboard where site owners install full-featured plugins from GitHub repositories, with no rebuild.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/rohittp0/NextPluggable.git",
8
+ "directory": "packages/nextpluggable"
9
+ },
10
+ "homepage": "https://github.com/rohittp0/NextPluggable#readme",
11
+ "bugs": "https://github.com/rohittp0/NextPluggable/issues",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "engines": {
16
+ "node": ">=20.16"
17
+ },
18
+ "type": "module",
19
+ "bin": {
20
+ "nextpluggable": "./bin/nextpluggable.js"
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "bin"
31
+ ],
32
+ "dependencies": {
33
+ "@nextpluggable/plugin": "0.1.1"
34
+ },
35
+ "peerDependencies": {
36
+ "next": ">=15.0.0",
37
+ "react": ">=19.0.0",
38
+ "react-dom": ">=19.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/react": "^19.2.0",
42
+ "@types/react-dom": "^19.2.0",
43
+ "next": "16.4.6",
44
+ "react": "19.3.1",
45
+ "react-dom": "19.3.1"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -p tsconfig.json",
49
+ "typecheck": "tsc -p tsconfig.json --noEmit"
50
+ }
6
51
  }