renusify 3.0.2 → 3.1.3

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.
@@ -4,7 +4,7 @@
4
4
  v-scroll="{handler:onScroll,target:target}"
5
5
  :style="{'max-height': height,'height': height}"
6
6
  :class="{'overflow-div':height}" class="infinite-page-container">
7
- <transition-group :class="{'flex-column-reverse':isChat}"
7
+ <transition-group v-if="!noItem" :class="{'flex-column-reverse':isChat}"
8
8
  :name="isChat?'slide-up':'slide-down'"
9
9
  class="row"
10
10
  tag="div">
@@ -16,23 +16,17 @@
16
16
  </r-col>
17
17
  </transition-group>
18
18
  </div>
19
- <div v-if="noItem"
20
- class="text-center title-2"
21
- >{{ noItemMsg }}
22
- </div>
19
+ <!-- noItem slot for empty contents. Provide noItem, noItemMsg props -->
20
+ <slot :noItem="noItem" :noItemMsg="noItemMsg" name="noItem">
21
+ <div v-if="noItem"
22
+ class="text-center title-2"
23
+ >{{ noItemMsg }}
24
+ </div>
25
+ </slot>
23
26
  </r-container>
24
27
  </template>
25
28
  <script setup>
26
- import {
27
- ref,
28
- computed,
29
- onMounted,
30
- onUnmounted,
31
- onActivated,
32
- onDeactivated,
33
- watch,
34
- inject, nextTick
35
- } from 'vue'
29
+ import {computed, inject, nextTick, onActivated, onDeactivated, onMounted, onUnmounted, ref, watch} from 'vue'
36
30
 
37
31
  const props = defineProps({
38
32
  /**
@@ -259,7 +259,7 @@
259
259
  </template>
260
260
 
261
261
  <script setup>
262
- import {ref, computed, watch, onMounted, inject} from 'vue'
262
+ import {computed, inject, onMounted, ref, watch} from 'vue'
263
263
  import ManageFooter from "./footer.vue";
264
264
  import ManageHeader from "./header.vue";
265
265
 
@@ -543,8 +543,6 @@ const sortSetup = (item) => {
543
543
  const ok = () => {
544
544
  table.value.startTime = false
545
545
  page.value = 1
546
- sortBy.value = null
547
- sortType.value = 0
548
546
  autoSend.value = false
549
547
  showForm.value = false
550
548
  refresh()
@@ -1,4 +1,4 @@
1
- import 'renusify/directive/animate/style.scss'
1
+ import './style.scss'
2
2
 
3
3
  /**
4
4
  * @example // v-animate usage
package/index.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ // Auto-generated Vue component type declarations
2
+ // Do not edit manually - run `npm run build` to update
3
+ declare module 'vue' {
4
+ export interface GlobalComponents {
5
+ rApp: typeof import('./components/app/index.js')['rApp']
6
+ rAvatar: typeof import('./components/avatar/index.js')['rAvatar']
7
+ rBtn: typeof import('./components/button/index.js')['rBtn']
8
+ rBtnConfirm: typeof import('./components/button/buttonConfirm.js')['rBtnConfirm']
9
+ rBtnGroup: typeof import('./components/button/buttonGroup.js')['rBtnGroup']
10
+ rCalendar: typeof import('./components/calendar/index.js')['rCalendar']
11
+ rCard: typeof import('./components/card/index.js')['rCard']
12
+ rCodeEditor: typeof import('./components/codeEditor/index.js')['rCodeEditor']
13
+ rConfirm: typeof import('./components/confirm/index.js')['rConfirm']
14
+ rContainer: typeof import('./components/container/index.js')['rContainer']
15
+ rRow: typeof import('./components/container/row.js')['rRow']
16
+ rCol: typeof import('./components/container/col.js')['rCol']
17
+ rSpacer: typeof import('./components/container/spacer.js')['rSpacer']
18
+ rDivider: typeof import('./components/container/divider.js')['rDivider']
19
+ rContent: typeof import('./components/content/index.js')['rContent']
20
+ rCropper: typeof import('./components/cropper/index.js')['rCropper']
21
+ rFloat: typeof import('./components/float/index.js')['rFloat']
22
+ rForm: typeof import('./components/form/index.js')['rForm']
23
+ rInput: typeof import('./components/form/input/index.js')['rInput']
24
+ rColorInput: typeof import('./components/form/colorInput/index.js')['rColorInput']
25
+ rDateInput: typeof import('./components/form/dateInput/index.js')['rDateInput']
26
+ rFileInput: typeof import('./components/form/fileInput/index.js')['rFileInput']
27
+ rTelInput: typeof import('./components/form/telInput/index.js')['rTelInput']
28
+ rJsonInput: typeof import('./components/form/jsonInput/index.js')['rJsonInput']
29
+ rTextEditor: typeof import('./components/form/textEditor/index.js')['rTextEditor']
30
+ rTextEditorPreview: typeof import('./components/form/textEditor/preview.js')['rTextEditorPreview']
31
+ rTimeInput: typeof import('./components/form/timeInput/index.js')['rTimeInput']
32
+ rTimeRangeInput: typeof import('./components/form/timeInput/range.js')['rTimeRangeInput']
33
+ rUniqueInput: typeof import('./components/form/uniqueInput/index.js')['rUniqueInput']
34
+ rAddressInput: typeof import('./components/form/addressInput/index.js')['rAddressInput']
35
+ rCamInput: typeof import('./components/form/camInput/index.js')['rCamInput']
36
+ rCheckInput: typeof import('./components/form/checkInput/index.js')['rCheckInput']
37
+ rCheckboxInput: typeof import('./components/form/checkboxInput/index.js')['rCheckboxInput']
38
+ rGroupInput: typeof import('./components/form/groupInput/index.js')['rGroupInput']
39
+ rMaskInput: typeof import('./components/form/maskInput/index.js')['rMaskInput']
40
+ rNumberInput: typeof import('./components/form/numberInput/index.js')['rNumberInput']
41
+ rPasswordInput: typeof import('./components/form/passwordInput/index.js')['rPasswordInput']
42
+ rRadioInput: typeof import('./components/form/radioInput/index.js')['rRadioInput']
43
+ rRangeInput: typeof import('./components/form/rangeInput/index.js')['rRangeInput']
44
+ rRatingInput: typeof import('./components/form/ratingInput/index.js')['rRatingInput']
45
+ rSelectInput: typeof import('./components/form/selectInput/index.js')['rSelectInput']
46
+ rSwitchInput: typeof import('./components/form/switchInput/index.js')['rSwitchInput']
47
+ rTextArea: typeof import('./components/form/textArea/index.js')['rTextArea']
48
+ rTextInput: typeof import('./components/form/textInput/index.js')['rTextInput']
49
+ rUnitInput: typeof import('./components/form/unitInput/index.js')['rUnitInput']
50
+ rFormCreator: typeof import('./components/formCreator/index.js')['rFormCreator']
51
+ rIcon: typeof import('./components/icon/index.js')['rIcon']
52
+ rImg: typeof import('./components/img/index.js')['rImg']
53
+ rInfinite: typeof import('./components/infinite/index.js')['rInfinite']
54
+ rMap: typeof import('./components/map/index.js')['rMap']
55
+ rMapSelect: typeof import('./components/map/select.js')['rMapSelect']
56
+ rMapRoute: typeof import('./components/map/route.js')['rMapRoute']
57
+ rMenu: typeof import('./components/menu/index.js')['rMenu']
58
+ rMeta: typeof import('./components/meta/index.js')['rMeta']
59
+ rModal: typeof import('./components/modal/index.js')['rModal']
60
+ rNotify: typeof import('./components/notify/index.js')['rNotify']
61
+ rProgressCircle: typeof import('./components/progress/circle.js')['rProgressCircle']
62
+ rProgressLine: typeof import('./components/progress/line.js')['rProgressLine']
63
+ rSearchBox: typeof import('./components/searchBox/index.js')['rSearchBox']
64
+ rSlider: typeof import('./components/slider/index.js')['rSlider']
65
+ rSwiper: typeof import('./components/swiper/index.js')['rSwiper']
66
+ rTable: typeof import('./components/table/index.js')['rTable']
67
+ rTableCrud: typeof import('./components/table/crud/index.js')['rTableCrud']
68
+ rTimeAgo: typeof import('./components/timeAgo/index.js')['rTimeAgo']
69
+ rTour: typeof import('./components/tour/index.js')['rTour']
70
+ rTree: typeof import('./components/tree/index.js')['rTree']
71
+ rHighlight: typeof import('./components/highlight/index.js')['rHighlight']
72
+ }
73
+ }
package/package.json CHANGED
@@ -1,30 +1,38 @@
1
- {
2
- "name": "renusify",
3
- "version": "3.0.2",
4
- "description": "Vue3 Framework",
5
- "keywords": [
6
- "vuejs",
7
- "vue framework",
8
- "ui framework",
9
- "component framework",
10
- "ui library",
11
- "component library",
12
- "material components",
13
- "renusify"
14
- ],
15
- "homepage": "https://github.com/smkoBa/renusify",
16
- "main": "index.js",
17
- "repository": {
18
- "type": "git",
19
- "url": "https://github.com/smkoBa/renusify.git"
20
- },
21
- "author": {
22
- "name": "Smko Bayazidi",
23
- "email": "ba.smko@gmail.com"
24
- },
25
- "license": "BSD",
26
- "private": false,
27
- "scripts": {
28
- "docs:generate": "node scripts/generate-docs.mjs"
29
- }
30
- }
1
+ {
2
+ "name": "renusify",
3
+ "version": "3.1.3",
4
+ "description": "Vue3 Framework",
5
+ "keywords": [
6
+ "vuejs",
7
+ "vue framework",
8
+ "ui framework",
9
+ "component framework",
10
+ "ui library",
11
+ "component library",
12
+ "material components",
13
+ "renusify"
14
+ ],
15
+ "homepage": "https://github.com/smkoBa/renusify",
16
+ "main": "index.js",
17
+ "types": "index.d.ts",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/smkoBa/renusify.git"
21
+ },
22
+ "author": {
23
+ "name": "Smko Bayazidi",
24
+ "email": "ba.smko@gmail.com"
25
+ },
26
+ "license": "BSD",
27
+ "private": false,
28
+ "scripts": {
29
+ "docs:generate": "node scripts/generate-docs.mjs",
30
+ "build:types": "node scripts/generate-types.mjs",
31
+ "build": "npm run docs:generate && npm run build:types"
32
+ },
33
+ "peerDependencies": {
34
+ "sass": "^1.69.0",
35
+ "vue": "^3.3.0",
36
+ "vue-router": "^4.5.0"
37
+ }
38
+ }
@@ -0,0 +1,314 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ export default function renusifyAutoPlugin(options = {}) {
5
+ const { prefix = 'r', debug = false } = options
6
+
7
+ const state = {
8
+ usedComponents: new Set(),
9
+ usedDirectives: new Set(),
10
+ componentsMap: new Map(),
11
+ directivesMap: new Map(),
12
+ rootDir: '',
13
+ }
14
+
15
+
16
+ function parseExports(filePath, exclude = []) {
17
+ try {
18
+ const content = fs.readFileSync(filePath, 'utf-8')
19
+ const clean = content
20
+ .replace(/\/\*[\s\S]*?\*\//g, '')
21
+ .replace(/\/\/.*$/gm, '')
22
+
23
+ const regex = /export\s+\*\s+as\s+([a-zA-Z_]\w*)\s+from\s+['"]([^'"]+)['"]/g
24
+ const map = new Map()
25
+ let m
26
+ while ((m = regex.exec(clean)) !== null) {
27
+ const [, name, relPath] = m
28
+ if (exclude.includes(name)) continue
29
+ let p = relPath.replace(/^\.\//, '')
30
+ if (!p.match(/\.(js|vue|ts|mjs)$/)) p = `${p}/index.js`
31
+ map.set(name, p)
32
+ }
33
+ return map
34
+ } catch (err) {
35
+ console.warn(`[renusify-auto] Could not parse ${filePath}:`, err.message)
36
+ return new Map()
37
+ }
38
+ }
39
+
40
+
41
+ function kebab2camel(s) {
42
+ return s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase())
43
+ }
44
+
45
+
46
+ function scanFile(filePath) {
47
+ try {
48
+ const content = fs.readFileSync(filePath, 'utf-8')
49
+ const tmplMatch = content.match(/<template(?:\s[^>]*)?>([\s\S]*?)<\/template>/)
50
+ if (!tmplMatch) return
51
+
52
+ const tmpl = tmplMatch[1]
53
+
54
+ const tagRe = /<\s*\/?([a-zA-Z][a-zA-Z0-9-]*)/g
55
+ let m
56
+ while ((m = tagRe.exec(tmpl)) !== null) {
57
+ const tag = m[1]
58
+ if (!tag.startsWith(prefix)) continue
59
+ const camel = kebab2camel(tag)
60
+ if (state.componentsMap.has(camel)) state.usedComponents.add(camel)
61
+ else if (state.componentsMap.has(tag)) state.usedComponents.add(tag)
62
+ }
63
+
64
+ const dirRe = /\bv-([a-zA-Z][a-zA-Z0-9-]*)/g
65
+ const builtins = new Set([
66
+ 'model', 'if', 'else', 'else-if', 'for', 'show', 'bind', 'on',
67
+ 'slot', 'text', 'html', 'cloak', 'once', 'memo', 'pre'
68
+ ])
69
+
70
+ while ((m = dirRe.exec(tmpl)) !== null) {
71
+ const d = m[1]
72
+ if (builtins.has(d)) continue
73
+ const camel = kebab2camel(d)
74
+ const candidates = [d, camel, `v${camel.charAt(0).toUpperCase()}${camel.slice(1)}`]
75
+ for (const c of candidates) {
76
+ if (state.directivesMap.has(c)) {
77
+ state.usedDirectives.add(c)
78
+ break
79
+ }
80
+ }
81
+ }
82
+ } catch {
83
+ // ignore
84
+ }
85
+ }
86
+
87
+
88
+ function scanDirSync(dir) {
89
+ let entries
90
+ try {
91
+ entries = fs.readdirSync(dir, { withFileTypes: true })
92
+ } catch {
93
+ return
94
+ }
95
+ for (const entry of entries) {
96
+ const full = path.join(dir, entry.name)
97
+ if (entry.isDirectory()) {
98
+ if (['node_modules', 'dist', '.git', '.nuxt', '.output'].includes(entry.name)) continue
99
+ scanDirSync(full)
100
+ } else if (entry.name.endsWith('.vue')) {
101
+ scanFile(full)
102
+ }
103
+ }
104
+ }
105
+
106
+
107
+ function generateImportStatements() {
108
+ const comps = [...state.usedComponents].sort()
109
+ const dirs = [...state.usedDirectives].sort()
110
+
111
+ if (comps.length === 0 && dirs.length === 0) return ''
112
+
113
+ let code = '\n'
114
+ if (comps.length > 0) {
115
+ code += `import {\n ${comps.join(',\n ')}\n} from 'renusify/components/index.js'\n`
116
+ }
117
+ if (dirs.length > 0) {
118
+ const dirNames = dirs.map(name => {
119
+ if (name.startsWith('v') || name.startsWith('V')) {
120
+ return name.charAt(1).toLowerCase() + name.slice(2)
121
+ }
122
+ return name
123
+ })
124
+ code += `import { ${dirNames.join(', ')} } from 'renusify/directive/index.js'\n`
125
+ }
126
+
127
+ return code
128
+ }
129
+
130
+
131
+ function generateComponentsObject() {
132
+ const comps = [...state.usedComponents].sort()
133
+ if (comps.length === 0) return null
134
+ return `components: {\n ${comps.join(',\n ')}\n }`
135
+ }
136
+
137
+
138
+ function generateDirectivesObject() {
139
+ const dirs = [...state.usedDirectives].sort()
140
+ if (dirs.length === 0) return null
141
+ const dirNames = dirs.map(name => {
142
+ if (name.startsWith('v') || name.startsWith('V')) {
143
+ return name.charAt(1).toLowerCase() + name.slice(2)
144
+ }
145
+ return name
146
+ })
147
+ return `directives: { ${dirNames.join(', ')} }`
148
+ }
149
+
150
+ return {
151
+ name: 'vite-plugin-renusify-auto',
152
+ enforce: 'pre',
153
+
154
+ configResolved(config) {
155
+ state.rootDir = config.root
156
+ const renusifyPath = path.join(config.root, 'node_modules/renusify')
157
+
158
+ state.componentsMap = parseExports(
159
+ path.join(renusifyPath, 'components/index.js'),
160
+ ['_register']
161
+ )
162
+ state.directivesMap = parseExports(
163
+ path.join(renusifyPath, 'directive/index.js'),
164
+ ['_registers']
165
+ )
166
+
167
+ if (config.command === 'serve') {
168
+ state.usedComponents = new Set(state.componentsMap.keys())
169
+ state.usedDirectives = new Set(state.directivesMap.keys())
170
+ if (debug) {
171
+ console.log(`[renusify-auto] Dev mode: ALL ${state.componentsMap.size} components, ${state.directivesMap.size} directives`)
172
+ }
173
+ } else {
174
+ scanDirSync(path.join(config.root, 'src'))
175
+ if (debug) {
176
+ console.log(`[renusify-auto] Build mode: ${state.usedComponents.size} components, ${state.usedDirectives.size} directives`)
177
+ console.log(' Components:', [...state.usedComponents].join(', '))
178
+ console.log(' Directives:', [...state.usedDirectives].join(', '))
179
+ }
180
+ }
181
+ },
182
+
183
+ transform(code, id) {
184
+ if (!/main\.(js|ts)$/.test(id)) return null
185
+ if (id.includes('node_modules')) return null
186
+
187
+ let newCode = code
188
+ let modified = false
189
+
190
+ const importStmts = generateImportStatements()
191
+ if (importStmts) {
192
+ const importRegex = /^import\s+[^;]+;?\s*$/gm
193
+ const allImports = code.match(importRegex)
194
+
195
+ if (allImports && allImports.length > 0) {
196
+ const lastImport = allImports[allImports.length - 1]
197
+ const lastImportIndex = code.lastIndexOf(lastImport)
198
+ const insertPos = lastImportIndex + lastImport.length
199
+ newCode = newCode.slice(0, insertPos) + importStmts + newCode.slice(insertPos)
200
+ } else {
201
+ newCode = importStmts + '\n' + newCode
202
+ }
203
+ modified = true
204
+ }
205
+
206
+ const renusifyRegex = /\.use\s*\(\s*renusify\s*,\s*\{/
207
+ const useMatch = newCode.match(renusifyRegex)
208
+
209
+ if (useMatch) {
210
+ const matchIndex = useMatch.index
211
+ const startOfOptions = matchIndex + useMatch[0].length
212
+
213
+ let braceCount = 1
214
+ let i = startOfOptions
215
+ while (i < newCode.length && braceCount > 0) {
216
+ if (newCode[i] === '{') braceCount++
217
+ else if (newCode[i] === '}') braceCount--
218
+ if (braceCount > 0) i++
219
+ }
220
+
221
+ if (braceCount === 0) {
222
+ const endOfOptions = i
223
+ const optionsContent = newCode.slice(startOfOptions, endOfOptions)
224
+ let cleanedOptions = optionsContent
225
+
226
+ cleanedOptions = removeProperty(cleanedOptions, 'components')
227
+ cleanedOptions = removeProperty(cleanedOptions, 'directives')
228
+
229
+ cleanedOptions = cleanedOptions.replace(/,(\s*)}/g, '$1}')
230
+ cleanedOptions = cleanedOptions.trim()
231
+
232
+ const componentsObj = generateComponentsObject()
233
+ const directivesObj = generateDirectivesObject()
234
+
235
+ let newOptionsContent = cleanedOptions
236
+
237
+ if (componentsObj || directivesObj) {
238
+ const needsComma = newOptionsContent.trim().length > 0 && !newOptionsContent.trim().endsWith(',')
239
+ const comma = needsComma ? ',' : ''
240
+
241
+ let additions = ''
242
+ if (componentsObj) additions += '\n ' + componentsObj
243
+ if (directivesObj) additions += (additions ? ',' : '') + '\n ' + directivesObj
244
+
245
+ if (newOptionsContent.trim().length === 0) {
246
+ newOptionsContent = additions + '\n '
247
+ } else {
248
+ newOptionsContent = newOptionsContent + comma + additions + '\n '
249
+ }
250
+ }
251
+
252
+ newCode = newCode.slice(0, startOfOptions) + newOptionsContent + newCode.slice(endOfOptions)
253
+ modified = true
254
+ }
255
+ }
256
+
257
+ if (modified) {
258
+ if (debug) {
259
+ console.log(`[renusify-auto] Transformed ${path.basename(id)}`)
260
+ }
261
+ return { code: newCode, map: null }
262
+ }
263
+
264
+ return null
265
+ },
266
+ }
267
+ }
268
+
269
+ function removeProperty(optionsStr, propName) {
270
+ const propRegex = new RegExp(`,?\\s*${propName}\\s*:\\s*`)
271
+ const match = propRegex.exec(optionsStr)
272
+
273
+ if (!match) return optionsStr
274
+
275
+ const startIndex = match.index
276
+ const valueStart = startIndex + match[0].length
277
+
278
+
279
+ let endIndex = valueStart
280
+ const firstChar = optionsStr[valueStart]
281
+
282
+ if (firstChar === '{') {
283
+
284
+ let braceCount = 1
285
+ let i = valueStart + 1
286
+ while (i < optionsStr.length && braceCount > 0) {
287
+ if (optionsStr[i] === '{') braceCount++
288
+ else if (optionsStr[i] === '}') braceCount--
289
+ i++
290
+ }
291
+ endIndex = i
292
+ } else if (firstChar === '[') {
293
+ let bracketCount = 1
294
+ let i = valueStart + 1
295
+ while (i < optionsStr.length && bracketCount > 0) {
296
+ if (optionsStr[i] === '[') bracketCount++
297
+ else if (optionsStr[i] === ']') bracketCount--
298
+ i++
299
+ }
300
+ endIndex = i
301
+ } else {
302
+ let i = valueStart
303
+ while (i < optionsStr.length && optionsStr[i] !== ',' && optionsStr[i] !== '}') {
304
+ i++
305
+ }
306
+ endIndex = i
307
+ }
308
+
309
+ if (endIndex < optionsStr.length && optionsStr[endIndex] === ',') {
310
+ endIndex++
311
+ }
312
+
313
+ return optionsStr.slice(0, startIndex) + optionsStr.slice(endIndex)
314
+ }
@@ -1,35 +1,164 @@
1
1
  class Storage {
2
- stringfy(value){
3
- return JSON.stringify(value)
2
+ constructor(encryptionKey) {
3
+ this._key = encryptionKey || this._loadKeyFromEnv();
4
+ this._available = this._checkAvailability();
5
+ if (!this._key) {
6
+ console.warn('[Storage] ⚠️ No encryption key provided. Safe methods will throw.');
4
7
  }
5
- parse(value){
6
- return JSON.parse(value)
7
- }
8
- set(key, value) {
9
- localStorage.setItem(key,this.stringfy(value))
8
+ }
9
+
10
+ _loadKeyFromEnv() {
11
+ if (typeof import.meta !== 'undefined' && import.meta.env?.VITE_STORAGE_KEY)
12
+ return import.meta.env.VITE_STORAGE_KEY;
13
+ if (typeof process !== 'undefined' && process.env?.STORAGE_KEY)
14
+ return process.env.STORAGE_KEY;
15
+ return null;
16
+ }
17
+
18
+ _checkAvailability() {
19
+ try {
20
+ const test = '__storage_test__';
21
+ localStorage.setItem(test, '1');
22
+ localStorage.removeItem(test);
23
+ return true;
24
+ } catch {
25
+ return false;
10
26
  }
27
+ }
28
+
29
+ _arrayBufferToBase64(buffer) {
30
+ const bytes = new Uint8Array(buffer);
31
+ let binary = '';
32
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
33
+ return btoa(binary);
34
+ }
35
+
36
+ _base64ToArrayBuffer(base64) {
37
+ const binary = atob(base64);
38
+ const bytes = new Uint8Array(binary.length);
39
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
40
+ return bytes.buffer;
41
+ }
42
+
43
+ async _deriveKey(password, salt) {
44
+ const enc = new TextEncoder();
45
+ const keyMaterial = await crypto.subtle.importKey(
46
+ 'raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']
47
+ );
48
+ return crypto.subtle.deriveKey(
49
+ {name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256'},
50
+ keyMaterial,
51
+ {name: 'AES-GCM', length: 256},
52
+ false,
53
+ ['encrypt', 'decrypt']
54
+ );
55
+ }
56
+
57
+ async _encrypt(plaintext) {
58
+ const salt = crypto.getRandomValues(new Uint8Array(16));
59
+ const iv = crypto.getRandomValues(new Uint8Array(12));
60
+ const key = await this._deriveKey(this._key, salt);
61
+ const cipher = await crypto.subtle.encrypt(
62
+ {name: 'AES-GCM', iv}, key, new TextEncoder().encode(plaintext)
63
+ );
64
+ return JSON.stringify({
65
+ salt: this._arrayBufferToBase64(salt),
66
+ iv: this._arrayBufferToBase64(iv),
67
+ data: this._arrayBufferToBase64(cipher)
68
+ });
69
+ }
11
70
 
12
- has(key) {
13
- return this.get(key)!==null
71
+ async _decrypt(payloadString) {
72
+ const {salt, iv, data} = JSON.parse(payloadString);
73
+ const key = await this._deriveKey(this._key, this._base64ToArrayBuffer(salt));
74
+ const decrypted = await crypto.subtle.decrypt(
75
+ {name: 'AES-GCM', iv: this._base64ToArrayBuffer(iv)},
76
+ key,
77
+ this._base64ToArrayBuffer(data)
78
+ );
79
+ return new TextDecoder().decode(decrypted);
80
+ }
81
+
82
+ stringify(value) {
83
+ return JSON.stringify(value);
84
+ }
85
+
86
+ parse(value) {
87
+ return JSON.parse(value);
88
+ }
89
+
90
+ set(key, value) {
91
+ if (!this._available) return false;
92
+ try {
93
+ localStorage.setItem(String(key), this.stringify(value));
94
+ return true;
95
+ } catch (err) {
96
+ console.error(`[Storage] set failed:`, err);
97
+ return false;
14
98
  }
99
+ }
100
+
101
+ has(key) {
102
+ if (!this._available) return false;
103
+ return localStorage.getItem(String(key)) !== null;
104
+ }
15
105
 
16
- get(key,def=null) {
17
- let i=localStorage.getItem(key)
18
- if(i===null){
19
- return def
20
- }
21
- return this.parse(i)
106
+ get(key, def = null) {
107
+ if (!this._available) return def;
108
+ const raw = localStorage.getItem(String(key));
109
+ if (raw === null) return def;
110
+ try {
111
+ return this.parse(raw);
112
+ } catch {
113
+ return def;
22
114
  }
115
+ }
23
116
 
24
- remove(key) {
25
- return localStorage.removeItem(key)
117
+ remove(key) {
118
+ if (!this._available) return false;
119
+ localStorage.removeItem(String(key));
120
+ return true;
121
+ }
122
+
123
+ pull(key, def = null) {
124
+ const data = this.get(key, def);
125
+ this.remove(key);
126
+ return data;
127
+ }
128
+
129
+ async setSafe(key, value) {
130
+ if (!this._key) throw new Error('[Storage] Encryption key not configured.');
131
+ if (!this._available) return false;
132
+ try {
133
+ const plaintext = this.stringify(value);
134
+ const encrypted = await this._encrypt(plaintext);
135
+ localStorage.setItem(String(key), encrypted);
136
+ return true;
137
+ } catch (err) {
138
+ console.error(`[Storage] setSafe failed:`, err);
139
+ return false;
26
140
  }
141
+ }
27
142
 
28
- pull(key){
29
- const d=this.get(key)
30
- this.remove(key)
31
- return d
143
+ async getSafe(key, def = null) {
144
+ if (!this._key) throw new Error('[Storage] Encryption key not configured.');
145
+ if (!this._available) return def;
146
+ const raw = localStorage.getItem(String(key));
147
+ if (raw === null) return def;
148
+ try {
149
+ const decrypted = await this._decrypt(raw);
150
+ return this.parse(decrypted);
151
+ } catch (err) {
152
+ console.warn(`[Storage] getSafe failed (tampered/invalid):`, err);
153
+ return def;
32
154
  }
155
+ }
156
+
157
+ async pullSafe(key, def = null) {
158
+ const data = await this.getSafe(key, def);
159
+ this.remove(key);
160
+ return data;
161
+ }
33
162
  }
34
163
 
35
- export default new Storage();
164
+ export default new Storage();
@@ -0,0 +1,83 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+
8
+ const CONFIG = {
9
+ inputFile: path.resolve(__dirname, '../components/index.js'),
10
+ outputFile: path.resolve(__dirname, '../index.d.ts'),
11
+ importPathPrefix: './components',
12
+ };
13
+
14
+
15
+ function parseExports(content) {
16
+ return content
17
+ .split('\n')
18
+ .map(line => line.trim())
19
+ .filter(line => line && !line.startsWith('//'))
20
+ .map(line => {
21
+ const match = line.match(/^export\s+\*\s+as\s+(\w+)\s+from\s+['"](.+)['"]\s*;?$/);
22
+ return match ? { componentName: match[1], relativePath: match[2] } : null;
23
+ })
24
+ .filter(item => item !== null);
25
+ }
26
+
27
+
28
+ function transformImportPath(relativePath, prefix) {
29
+ if (relativePath.startsWith('./')) {
30
+ return `${prefix}${relativePath.slice(1)}`;
31
+ }
32
+ return relativePath;
33
+ }
34
+
35
+
36
+ function generateDeclaration(components, prefix) {
37
+ const lines = [
38
+ '// Auto-generated Vue component type declarations',
39
+ '// Do not edit manually - run `npm run build` to update',
40
+ `declare module 'vue' {`,
41
+ ` export interface GlobalComponents {`,
42
+ ];
43
+
44
+ for (const { componentName, relativePath } of components) {
45
+ const importPath = transformImportPath(relativePath, prefix);
46
+ lines.push(` ${componentName}: typeof import('${importPath}')['${componentName}']`);
47
+ }
48
+
49
+ lines.push(` }`, `}`, '');
50
+ return lines.join('\n');
51
+ }
52
+
53
+
54
+ function main() {
55
+ try {
56
+ console.log(`Reading exports from: ${CONFIG.inputFile}`);
57
+
58
+ if (!fs.existsSync(CONFIG.inputFile)) {
59
+ throw new Error(`Input file not found: ${CONFIG.inputFile}`);
60
+ }
61
+
62
+ const content = fs.readFileSync(CONFIG.inputFile, 'utf-8');
63
+ const components = parseExports(content);
64
+
65
+ if (components.length === 0) {
66
+ console.warn('No component exports found. Check your input file format.');
67
+ } else {
68
+ console.log(`Found ${components.length} component exports`);
69
+ }
70
+
71
+ const declaration = generateDeclaration(components, CONFIG.importPathPrefix);
72
+
73
+ fs.writeFileSync(CONFIG.outputFile, declaration, 'utf-8');
74
+ console.log(`Generated: ${CONFIG.outputFile}`);
75
+ console.log(`Total components: ${components.length}`);
76
+
77
+ } catch (error) {
78
+ console.error('Error:', error.message);
79
+ process.exit(1);
80
+ }
81
+ }
82
+
83
+ main();