@sfxcode/nuxt-ui-mongocamp 1.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/module.d.mts +8 -0
  4. package/dist/module.json +12 -0
  5. package/dist/module.mjs +35 -0
  6. package/dist/runtime/components/MongocampAccount.d.vue.ts +3 -0
  7. package/dist/runtime/components/MongocampAccount.vue +197 -0
  8. package/dist/runtime/components/MongocampAccount.vue.d.ts +3 -0
  9. package/dist/runtime/components/MongocampCollectionData.d.vue.ts +6 -0
  10. package/dist/runtime/components/MongocampCollectionData.vue +511 -0
  11. package/dist/runtime/components/MongocampCollectionData.vue.d.ts +6 -0
  12. package/dist/runtime/components/MongocampCollectionInfos.d.vue.ts +9 -0
  13. package/dist/runtime/components/MongocampCollectionInfos.vue +393 -0
  14. package/dist/runtime/components/MongocampCollectionInfos.vue.d.ts +9 -0
  15. package/dist/runtime/components/MongocampCollections.d.vue.ts +7 -0
  16. package/dist/runtime/components/MongocampCollections.vue +231 -0
  17. package/dist/runtime/components/MongocampCollections.vue.d.ts +7 -0
  18. package/dist/runtime/components/MongocampDatabases.d.vue.ts +3 -0
  19. package/dist/runtime/components/MongocampDatabases.vue +112 -0
  20. package/dist/runtime/components/MongocampDatabases.vue.d.ts +3 -0
  21. package/dist/runtime/components/MongocampJobs.d.vue.ts +3 -0
  22. package/dist/runtime/components/MongocampJobs.vue +354 -0
  23. package/dist/runtime/components/MongocampJobs.vue.d.ts +3 -0
  24. package/dist/runtime/components/MongocampLogin.d.vue.ts +3 -0
  25. package/dist/runtime/components/MongocampLogin.vue +63 -0
  26. package/dist/runtime/components/MongocampLogin.vue.d.ts +3 -0
  27. package/dist/runtime/components/MongocampRoleGrants.d.vue.ts +6 -0
  28. package/dist/runtime/components/MongocampRoleGrants.vue +276 -0
  29. package/dist/runtime/components/MongocampRoleGrants.vue.d.ts +6 -0
  30. package/dist/runtime/components/MongocampRoles.d.vue.ts +6 -0
  31. package/dist/runtime/components/MongocampRoles.vue +272 -0
  32. package/dist/runtime/components/MongocampRoles.vue.d.ts +6 -0
  33. package/dist/runtime/components/MongocampUsers.d.vue.ts +3 -0
  34. package/dist/runtime/components/MongocampUsers.vue +320 -0
  35. package/dist/runtime/components/MongocampUsers.vue.d.ts +3 -0
  36. package/dist/runtime/components/MongocampVersion.d.vue.ts +3 -0
  37. package/dist/runtime/components/MongocampVersion.vue +25 -0
  38. package/dist/runtime/components/MongocampVersion.vue.d.ts +3 -0
  39. package/dist/runtime/composables/useMongocampAccount.d.ts +7 -0
  40. package/dist/runtime/composables/useMongocampAccount.js +28 -0
  41. package/dist/runtime/composables/useMongocampAdmin.d.ts +14 -0
  42. package/dist/runtime/composables/useMongocampAdmin.js +48 -0
  43. package/dist/runtime/composables/useMongocampBucket.d.ts +15 -0
  44. package/dist/runtime/composables/useMongocampBucket.js +109 -0
  45. package/dist/runtime/composables/useMongocampCollection.d.ts +17 -0
  46. package/dist/runtime/composables/useMongocampCollection.js +12 -0
  47. package/dist/runtime/composables/useMongocampDocument.d.ts +13 -0
  48. package/dist/runtime/composables/useMongocampDocument.js +18 -0
  49. package/dist/runtime/composables/useMongocampDynamicForm.d.ts +14 -0
  50. package/dist/runtime/composables/useMongocampDynamicForm.js +231 -0
  51. package/dist/runtime/composables/useMongocampIndex.d.ts +9 -0
  52. package/dist/runtime/composables/useMongocampIndex.js +23 -0
  53. package/dist/runtime/composables/useMongocampJobs.d.ts +9 -0
  54. package/dist/runtime/composables/useMongocampJobs.js +25 -0
  55. package/dist/runtime/composables/useMongocampQuery.d.ts +99 -0
  56. package/dist/runtime/composables/useMongocampQuery.js +108 -0
  57. package/dist/runtime/composables/useMongocampQueryBuilder.d.ts +30 -0
  58. package/dist/runtime/composables/useMongocampQueryBuilder.js +112 -0
  59. package/dist/runtime/composables/useMongocampSchema.d.ts +14 -0
  60. package/dist/runtime/composables/useMongocampSchema.js +142 -0
  61. package/dist/runtime/composables/useMongocampSystem.d.ts +12 -0
  62. package/dist/runtime/composables/useMongocampSystem.js +21 -0
  63. package/dist/runtime/plugin.d.ts +6 -0
  64. package/dist/runtime/plugin.js +23 -0
  65. package/dist/runtime/server/tsconfig.json +3 -0
  66. package/dist/types.d.mts +3 -0
  67. package/package.json +99 -0
@@ -0,0 +1,142 @@
1
+ const DATE_TIME_STRING_REGEX = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
2
+ function isDateTimeString(value) {
3
+ return DATE_TIME_STRING_REGEX.test(value);
4
+ }
5
+ function isPlainObject(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ function detectValueType(value) {
9
+ if (value === null || value === void 0) return null;
10
+ if (typeof value === "boolean") return "boolean";
11
+ if (typeof value === "number") return "number";
12
+ if (typeof value === "string") return isDateTimeString(value) ? "date-time" : "string";
13
+ if (Array.isArray(value)) return "array";
14
+ if (isPlainObject(value)) {
15
+ if ("$date" in value) return "date-time";
16
+ if ("$oid" in value) return "string";
17
+ if ("$numberInt" in value || "$numberLong" in value || "$numberDouble" in value || "$numberDecimal" in value) return "number";
18
+ return "object";
19
+ }
20
+ return "string";
21
+ }
22
+ function orderFields(fields) {
23
+ const sortedFields = [];
24
+ if (fields.includes("_id")) {
25
+ sortedFields.push("_id");
26
+ }
27
+ sortedFields.push(...fields.filter((f) => f !== "_id" && f !== "metaData").sort());
28
+ if (fields.includes("metaData")) {
29
+ sortedFields.push("metaData");
30
+ }
31
+ return sortedFields;
32
+ }
33
+ function fieldsFromRecords(records) {
34
+ const fieldKeys = /* @__PURE__ */ new Set();
35
+ const fieldValueCounts = /* @__PURE__ */ new Map();
36
+ const fieldTypes = /* @__PURE__ */ new Map();
37
+ const fieldValues = /* @__PURE__ */ new Map();
38
+ records.forEach((record) => {
39
+ Object.entries(record).forEach(([key, value]) => {
40
+ fieldKeys.add(key);
41
+ const type = detectValueType(value);
42
+ if (type) {
43
+ fieldValueCounts.set(key, (fieldValueCounts.get(key) ?? 0) + 1);
44
+ if (!fieldTypes.has(key)) {
45
+ fieldTypes.set(key, /* @__PURE__ */ new Set());
46
+ }
47
+ fieldTypes.get(key).add(type);
48
+ }
49
+ if (value !== null && value !== void 0) {
50
+ if (!fieldValues.has(key)) {
51
+ fieldValues.set(key, []);
52
+ }
53
+ fieldValues.get(key).push(value);
54
+ }
55
+ });
56
+ });
57
+ return orderFields(Array.from(fieldKeys)).map((key) => {
58
+ const types = fieldTypes.get(key);
59
+ const columnType = types && types.size === 1 ? [...types][0] : "string";
60
+ const column = {
61
+ columnName: key,
62
+ columnKey: key,
63
+ columnType,
64
+ required: fieldValueCounts.get(key) === records.length
65
+ };
66
+ if (columnType === "object") {
67
+ const objectValues = (fieldValues.get(key) ?? []).filter(isPlainObject);
68
+ column.children = fieldsFromRecords(objectValues);
69
+ } else if (columnType === "array") {
70
+ const items = (fieldValues.get(key) ?? []).filter(Array.isArray).flat();
71
+ const itemTypes = /* @__PURE__ */ new Set();
72
+ items.forEach((item) => {
73
+ const itemType = detectValueType(item);
74
+ if (itemType) itemTypes.add(itemType);
75
+ });
76
+ column.arrayItemType = itemTypes.size === 1 ? [...itemTypes][0] : itemTypes.size === 0 ? "unknown" : "string";
77
+ if (column.arrayItemType === "object") {
78
+ column.children = fieldsFromRecords(items.filter(isPlainObject));
79
+ }
80
+ }
81
+ return column;
82
+ });
83
+ }
84
+ const TS_SCALAR_TYPES = {
85
+ "string": "string",
86
+ "number": "number",
87
+ "integer": "number",
88
+ "date-time": "string",
89
+ "boolean": "boolean"
90
+ };
91
+ const IDENTIFIER_REGEX = /^[a-z_$][\w$]*$/i;
92
+ function toPascalCase(value) {
93
+ const parts = value.split(/[^a-z0-9]+/i).filter(Boolean);
94
+ return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("") || "Document";
95
+ }
96
+ function singularize(word) {
97
+ if (/ies$/i.test(word)) return word.replace(/ies$/i, "y");
98
+ if (/(?:[sxz]|ch|sh)es$/i.test(word)) return word.replace(/es$/i, "");
99
+ if (/s$/i.test(word) && !/ss$/i.test(word)) return word.replace(/s$/i, "");
100
+ return word;
101
+ }
102
+ function tsTypeForColumn(col, parentName, extraInterfaces) {
103
+ if (col.columnType === "object") {
104
+ if (!col.children?.length) return "Record<string, unknown>";
105
+ const name = `${parentName}${toPascalCase(col.columnKey)}`;
106
+ extraInterfaces.push(buildInterfaceBlock(name, col.children, extraInterfaces));
107
+ return name;
108
+ }
109
+ if (col.columnType === "array") {
110
+ if (col.arrayItemType === "object") {
111
+ if (!col.children?.length) return "Record<string, unknown>[]";
112
+ const name = `${parentName}${toPascalCase(singularize(col.columnKey))}`;
113
+ extraInterfaces.push(buildInterfaceBlock(name, col.children, extraInterfaces));
114
+ return `${name}[]`;
115
+ }
116
+ const itemType = col.arrayItemType ? TS_SCALAR_TYPES[col.arrayItemType] ?? "unknown" : "unknown";
117
+ return `${itemType}[]`;
118
+ }
119
+ return TS_SCALAR_TYPES[col.columnType] ?? "unknown";
120
+ }
121
+ function buildInterfaceBlock(name, columns, extraInterfaces) {
122
+ const lines = columns.map((col) => {
123
+ const key = IDENTIFIER_REGEX.test(col.columnKey) ? col.columnKey : `'${col.columnKey}'`;
124
+ const optionalMarker = col.required ? "" : "?";
125
+ const tsType = tsTypeForColumn(col, name, extraInterfaces);
126
+ return ` ${key}${optionalMarker}: ${tsType}`;
127
+ });
128
+ return `interface ${name} {
129
+ ${lines.join("\n")}
130
+ }`;
131
+ }
132
+ export function useMongocampSchema() {
133
+ function schemaFromSamples(records) {
134
+ return fieldsFromRecords(records);
135
+ }
136
+ function schemaToTsInterface(columns, interfaceName) {
137
+ const extraInterfaces = [];
138
+ const rootBlock = buildInterfaceBlock(toPascalCase(interfaceName), columns, extraInterfaces);
139
+ return [rootBlock, ...extraInterfaces].join("\n\n");
140
+ }
141
+ return { schemaFromSamples, schemaToTsInterface };
142
+ }
@@ -0,0 +1,12 @@
1
+ import type { DatabaseInfo } from '@sfxcode/nuxt-mongocamp-server';
2
+ /**
3
+ * Read-only wrapper for databaseApi. Deliberately scoped to databases only —
4
+ * deleteDatabase is out of scope (cross-cutting, highly destructive), and
5
+ * applicationApi (settings/configuration) is not wrapped here at all for now.
6
+ */
7
+ export declare function useMongocampSystem(): {
8
+ listDatabases: () => Promise<string[]>;
9
+ getDatabaseInfos: () => Promise<DatabaseInfo[]>;
10
+ getDatabaseInfo: (databaseName: string) => Promise<DatabaseInfo>;
11
+ listCollectionsByDatabase: (databaseName: string) => Promise<string[]>;
12
+ };
@@ -0,0 +1,21 @@
1
+ import { useMongocampApi } from "#imports";
2
+ const REQUEST_TIMEOUT_MS = 15e3;
3
+ function withTimeout() {
4
+ return { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) };
5
+ }
6
+ export function useMongocampSystem() {
7
+ const { databaseApi } = useMongocampApi();
8
+ async function listDatabases() {
9
+ return databaseApi.listDatabases(withTimeout());
10
+ }
11
+ async function getDatabaseInfos() {
12
+ return databaseApi.databaseInfos(withTimeout());
13
+ }
14
+ async function getDatabaseInfo(databaseName) {
15
+ return databaseApi.getDatabaseInfo({ databaseName }, withTimeout());
16
+ }
17
+ async function listCollectionsByDatabase(databaseName) {
18
+ return databaseApi.listCollectionsByDatabase({ databaseName }, withTimeout());
19
+ }
20
+ return { listDatabases, getDatabaseInfos, getDatabaseInfo, listCollectionsByDatabase };
21
+ }
@@ -0,0 +1,6 @@
1
+ declare const _default: import("#app").Plugin<{
2
+ mongocampVersion: import("vue").Ref<import("@sfxcode/nuxt-mongocamp-server").Version | undefined, import("@sfxcode/nuxt-mongocamp-server").Version | undefined>;
3
+ }> & import("#app").ObjectPlugin<{
4
+ mongocampVersion: import("vue").Ref<import("@sfxcode/nuxt-mongocamp-server").Version | undefined, import("@sfxcode/nuxt-mongocamp-server").Version | undefined>;
5
+ }>;
6
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import { defineNuxtPlugin, addRouteMiddleware, navigateTo, useAsyncData } from "#app";
2
+ import { useMongocampStorage, useMongocampApi, useMongocampAuth } from "#imports";
3
+ export default defineNuxtPlugin(async (_nuxtApp) => {
4
+ const { logout, isLoggedIn } = useMongocampAuth();
5
+ const { informationApi } = useMongocampApi();
6
+ const state = useMongocampStorage();
7
+ const { data: version } = await useAsyncData("version", () => informationApi.version());
8
+ addRouteMiddleware("global-auth", (to) => {
9
+ if ((to.path.startsWith("/admin") || to.path.startsWith("/secured/admin")) && (!isLoggedIn.value || !state.value.profile.isAdmin)) {
10
+ return navigateTo("/secured");
11
+ } else if (to.path.startsWith("/secured") && !isLoggedIn.value) {
12
+ return navigateTo("/");
13
+ } else if (to.path === "/logout") {
14
+ logout();
15
+ return navigateTo("/");
16
+ }
17
+ }, { global: true });
18
+ return {
19
+ provide: {
20
+ mongocampVersion: version
21
+ }
22
+ };
23
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json",
3
+ }
@@ -0,0 +1,3 @@
1
+ export { default } from './module.mjs'
2
+
3
+ export { type ModuleOptions } from './module.mjs'
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@sfxcode/nuxt-ui-mongocamp",
3
+ "version": "1.1.0",
4
+ "description": "A Nuxt module that wraps @sfxcode/nuxt-mongocamp-server with ready-made UI components, composables, and a runtime plugin",
5
+ "repository": "sfxcode/nuxt-ui-mongocamp",
6
+ "homepage": "https://sfxcode.github.io/nuxt-ui-mongocamp/",
7
+ "bugs": "https://github.com/sfxcode/nuxt-ui-mongocamp/issues",
8
+ "author": "sfxcode",
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "nuxt",
12
+ "nuxt-module",
13
+ "mongocamp",
14
+ "mongodb",
15
+ "vue",
16
+ "nuxt-ui"
17
+ ],
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/types.d.mts",
22
+ "import": "./dist/module.mjs"
23
+ }
24
+ },
25
+ "main": "./dist/module.mjs",
26
+ "typesVersions": {
27
+ "*": {
28
+ ".": [
29
+ "./dist/types.d.mts"
30
+ ]
31
+ }
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "workspaces": [
37
+ "playground"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "prepack": "nuxt-module-build build",
44
+ "dev": "npm run dev:prepare && nuxt dev playground",
45
+ "dev:build": "nuxt build playground",
46
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt prepare playground",
47
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
48
+ "lint": "eslint .",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest watch",
51
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
52
+ "docs:dev": "vitepress dev docs",
53
+ "docs:build": "vitepress build docs",
54
+ "docs:preview": "vitepress preview docs"
55
+ },
56
+ "dependencies": {
57
+ "@nuxt/kit": "^4.4.8",
58
+ "@internationalized/date": "^3.12.2",
59
+ "@nuxt/ui": "4.9.0",
60
+ "@sfxcode/nuxt-mongocamp-server": "^1.4.4",
61
+ "@sfxcode/nuxt-ui-formkit": "^1.1.1",
62
+ "unocss-nuxt-ui": "1.2.1"
63
+ },
64
+ "devDependencies": {
65
+ "@nuxt/devtools": "4.0.0-alpha.7",
66
+ "@nuxt/eslint-config": "^1.16.0",
67
+ "@nuxt/module-builder": "^1.0.2",
68
+ "@nuxt/schema": "^4.4.8",
69
+ "@nuxt/test-utils": "^4.0.3",
70
+ "@nuxt/ui": "4.9.0",
71
+ "@tiptap/core": "^3.27.1",
72
+ "@tiptap/extension-bubble-menu": "^3.27.1",
73
+ "@tiptap/extension-code": "^3.27.1",
74
+ "@tiptap/extension-collaboration": "^3.27.1",
75
+ "@tiptap/extension-drag-handle": "^3.27.1",
76
+ "@tiptap/extension-drag-handle-vue-3": "^3.27.1",
77
+ "@tiptap/extension-floating-menu": "^3.27.1",
78
+ "@tiptap/extension-horizontal-rule": "^3.27.1",
79
+ "@tiptap/extension-image": "^3.27.1",
80
+ "@tiptap/extension-mention": "^3.27.1",
81
+ "@tiptap/extension-node-range": "^3.27.1",
82
+ "@tiptap/extension-placeholder": "^3.27.1",
83
+ "@tiptap/markdown": "^3.27.1",
84
+ "@tiptap/pm": "^3.27.1",
85
+ "@tiptap/starter-kit": "^3.27.1",
86
+ "@tiptap/suggestion": "^3.27.1",
87
+ "@tiptap/vue-3": "^3.27.1",
88
+ "@types/node": "latest",
89
+ "changelogen": "^0.6.2",
90
+ "eslint": "^10.6.0",
91
+ "nuxt": "^4.4.8",
92
+ "tailwindcss": "^4.3.2",
93
+ "typescript": "~6.0.3",
94
+ "vitepress": "^1.6.4",
95
+ "vitest": "^4.1.9",
96
+ "vue-tsc": "^3.3.6"
97
+ },
98
+ "packageManager": "pnpm@11.8.0+sha512.c1f5e7c4cb241c8f174b743851d82f42b802324afc8b0f116b96adb15aa06664948dde36960a3ba1079ba5b4b29dd0140135b94b5b5f5263592249d68e555f26"
99
+ }