com-angel-authorization 1.0.2 → 1.0.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.
package/dist/vue/index.js CHANGED
@@ -5,9 +5,110 @@ import {
5
5
  onScopeDispose,
6
6
  shallowRef
7
7
  } from "vue";
8
- import {
9
- createPermissionStore
10
- } from "../core";
8
+
9
+ // src/core/store.ts
10
+ var DEFAULT_STATE = {
11
+ permissions: [],
12
+ roles: [],
13
+ isSuperAdmin: false
14
+ };
15
+ function toArray(value) {
16
+ return Array.isArray(value) ? value : [value];
17
+ }
18
+ function matchCodes(owned, required, mode, isSuperAdmin) {
19
+ if (isSuperAdmin) return true;
20
+ if (required.length === 0) return true;
21
+ if (mode === "all") {
22
+ return required.every((code) => owned.has(code));
23
+ }
24
+ return required.some((code) => owned.has(code));
25
+ }
26
+ var PermissionStore = class {
27
+ constructor(initial) {
28
+ this.listeners = /* @__PURE__ */ new Set();
29
+ this.state = {
30
+ ...DEFAULT_STATE,
31
+ ...initial,
32
+ permissions: initial?.permissions ?? [],
33
+ roles: initial?.roles ?? []
34
+ };
35
+ this.permissionSet = new Set(this.state.permissions);
36
+ this.roleSet = new Set(this.state.roles);
37
+ }
38
+ getState() {
39
+ return {
40
+ permissions: [...this.state.permissions],
41
+ roles: [...this.state.roles],
42
+ isSuperAdmin: this.state.isSuperAdmin
43
+ };
44
+ }
45
+ setState(next) {
46
+ this.state = {
47
+ permissions: next.permissions ?? this.state.permissions,
48
+ roles: next.roles ?? this.state.roles,
49
+ isSuperAdmin: next.isSuperAdmin ?? this.state.isSuperAdmin
50
+ };
51
+ this.permissionSet = new Set(this.state.permissions);
52
+ this.roleSet = new Set(this.state.roles);
53
+ this.emit();
54
+ }
55
+ setPermissions(permissions) {
56
+ this.setState({ permissions });
57
+ }
58
+ setRoles(roles) {
59
+ this.setState({ roles });
60
+ }
61
+ setSuperAdmin(isSuperAdmin) {
62
+ this.setState({ isSuperAdmin });
63
+ }
64
+ /** Replace permissions, roles and super-admin flag in one shot (typical after login). */
65
+ hydrate(payload) {
66
+ this.setState({
67
+ permissions: payload.permissions ?? [],
68
+ roles: payload.roles ?? [],
69
+ isSuperAdmin: payload.isSuperAdmin ?? false
70
+ });
71
+ }
72
+ /** Clear all authz data (typical after logout). */
73
+ clear() {
74
+ this.hydrate({});
75
+ }
76
+ hasPermission(codes, options = {}) {
77
+ const mode = options.mode ?? "any";
78
+ return matchCodes(
79
+ this.permissionSet,
80
+ toArray(codes).filter(Boolean),
81
+ mode,
82
+ Boolean(this.state.isSuperAdmin)
83
+ );
84
+ }
85
+ hasRole(codes, options = {}) {
86
+ const mode = options.mode ?? "any";
87
+ return matchCodes(
88
+ this.roleSet,
89
+ toArray(codes).filter(Boolean),
90
+ mode,
91
+ Boolean(this.state.isSuperAdmin)
92
+ );
93
+ }
94
+ /** Alias of `hasPermission` for template-friendly APIs. */
95
+ can(codes, options) {
96
+ return this.hasPermission(codes, options);
97
+ }
98
+ subscribe(listener) {
99
+ this.listeners.add(listener);
100
+ return () => {
101
+ this.listeners.delete(listener);
102
+ };
103
+ }
104
+ emit() {
105
+ const snapshot = this.getState();
106
+ this.listeners.forEach((listener) => listener(snapshot));
107
+ }
108
+ };
109
+ function createPermissionStore(initial) {
110
+ return new PermissionStore(initial);
111
+ }
11
112
 
12
113
  // src/vue/directive.ts
13
114
  function parseBinding(binding) {
@@ -206,11 +307,287 @@ import {
206
307
  ref,
207
308
  watch
208
309
  } from "vue";
209
- import {
210
- RESOURCE_PRIVATE_OPTIONS,
211
- RESOURCE_STATUS_ENABLED,
212
- RESOURCE_STATUS_OPTIONS
213
- } from "../resources";
310
+
311
+ // src/resources/types.ts
312
+ var RESOURCE_TYPE_API = "api";
313
+ var RESOURCE_STATUS_ENABLED = 1;
314
+ var RESOURCE_STATUS_DISABLED = 0;
315
+ var RESOURCE_STATUS_OPTIONS = [
316
+ { label: "\u542F\u7528", value: RESOURCE_STATUS_ENABLED },
317
+ { label: "\u7981\u7528", value: RESOURCE_STATUS_DISABLED }
318
+ ];
319
+ var RESOURCE_PRIVATE_OPTIONS = [
320
+ { label: "\u662F", value: true },
321
+ { label: "\u5426", value: false }
322
+ ];
323
+
324
+ // src/utils/snowflake.ts
325
+ var DEVICE_WORKER_ID_KEY = "hgams_device_worker_id";
326
+ function generateDeviceWorkerId() {
327
+ const cached = localStorage.getItem(DEVICE_WORKER_ID_KEY);
328
+ if (cached !== null && cached !== "") {
329
+ return BigInt(cached);
330
+ }
331
+ const components = [
332
+ navigator.userAgent,
333
+ screen.width + "x" + screen.height,
334
+ screen.colorDepth,
335
+ navigator.language,
336
+ (/* @__PURE__ */ new Date()).getTimezoneOffset(),
337
+ navigator.hardwareConcurrency,
338
+ navigator.deviceMemory
339
+ ];
340
+ const fingerprint = components.join("|");
341
+ let hash = 0;
342
+ for (let i = 0; i < fingerprint.length; i++) {
343
+ hash = (hash << 5) - hash + fingerprint.charCodeAt(i);
344
+ hash |= 0;
345
+ }
346
+ const maxWorkerId = Math.pow(2, 14) - 1;
347
+ const workerId = Math.abs(hash % maxWorkerId);
348
+ const workerIdBigInt = BigInt(workerId);
349
+ localStorage.setItem(DEVICE_WORKER_ID_KEY, workerIdBigInt.toString());
350
+ return workerIdBigInt;
351
+ }
352
+ var ConfigurableSnowflake = class {
353
+ constructor({
354
+ epoch = 0n,
355
+ workerId = 0n,
356
+ processId = 0n,
357
+ workerIdBits = 5,
358
+ processIdBits = 5,
359
+ sequenceBits = 12
360
+ } = {}) {
361
+ this.sequence = 0n;
362
+ this.latestTimestamp = BigInt(Date.now());
363
+ this.epoch = epoch;
364
+ const workerIdBitsBig = BigInt(workerIdBits);
365
+ const processIdBitsBig = BigInt(processIdBits);
366
+ const sequenceBitsBig = BigInt(sequenceBits);
367
+ const workerIdMask = -1n ^ -1n << workerIdBitsBig;
368
+ const processIdMask = -1n ^ -1n << processIdBitsBig;
369
+ this.sequenceMask = -1n ^ -1n << sequenceBitsBig;
370
+ this.timestampLeftShift = sequenceBitsBig + workerIdBitsBig + processIdBitsBig;
371
+ this.workerIdShift = sequenceBitsBig + processIdBitsBig;
372
+ this.processIdShift = sequenceBitsBig;
373
+ this.workerId = workerId & workerIdMask;
374
+ this.processId = processId & processIdMask;
375
+ }
376
+ nextId() {
377
+ const timestamp = BigInt(Date.now());
378
+ if (this.latestTimestamp === timestamp) {
379
+ this.sequence = this.sequence + 1n & this.sequenceMask;
380
+ } else {
381
+ this.sequence = 0n;
382
+ this.latestTimestamp = timestamp;
383
+ }
384
+ return timestamp - this.epoch << this.timestampLeftShift | this.workerId << this.workerIdShift | this.processId << this.processIdShift | this.sequence;
385
+ }
386
+ };
387
+ var snowyflake = new ConfigurableSnowflake({
388
+ workerId: generateDeviceWorkerId(),
389
+ workerIdBits: 14,
390
+ processIdBits: 0,
391
+ sequenceBits: 8,
392
+ epoch: BigInt((/* @__PURE__ */ new Date("2026-06-08")).getTime())
393
+ });
394
+ function getAppClientId() {
395
+ return snowyflake.nextId().toString();
396
+ }
397
+ function getDeviceWorkerId() {
398
+ return snowyflake.workerId.toString();
399
+ }
400
+
401
+ // src/resources/pagination.ts
402
+ function appendQueryParam(parts, key, value) {
403
+ if (value !== void 0 && value !== null && String(value) !== "") {
404
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
405
+ }
406
+ }
407
+ function extractPagination(payload) {
408
+ if (!payload || typeof payload !== "object") {
409
+ return {
410
+ pageToken: "",
411
+ hasPreviousPage: false,
412
+ hasNextPage: false
413
+ };
414
+ }
415
+ const envelope = payload;
416
+ const pagination = envelope.pagination && typeof envelope.pagination === "object" ? envelope.pagination : envelope.page && typeof envelope.page === "object" ? envelope.page : null;
417
+ const rawPageToken = pagination?.["page-token"] ?? pagination?.pageToken ?? pagination?.nextPageToken ?? envelope["page-token"] ?? envelope.pageToken ?? "";
418
+ const pageToken = rawPageToken === void 0 || rawPageToken === null ? "" : String(rawPageToken);
419
+ const hasPreviousPage = Boolean(
420
+ pagination?.hasPreviousPage ?? pagination?.hasPrevious ?? pagination?.hasPre ?? pagination?.previous ?? envelope.hasPreviousPage ?? envelope.hasPrevious
421
+ );
422
+ const hasNextPage = Boolean(
423
+ pagination?.hasNextPage ?? pagination?.hasNext ?? pagination?.next ?? envelope.hasNextPage ?? envelope.hasNext
424
+ );
425
+ return {
426
+ pageToken,
427
+ hasPreviousPage,
428
+ hasNextPage
429
+ };
430
+ }
431
+ function extractRecords(payload) {
432
+ if (!payload) return [];
433
+ if (Array.isArray(payload)) return payload;
434
+ if (typeof payload === "object") {
435
+ const envelope = payload;
436
+ const data = envelope.data;
437
+ if (Array.isArray(data)) return data;
438
+ if (data && typeof data === "object") {
439
+ const nested = data;
440
+ if (Array.isArray(nested.records)) return nested.records;
441
+ if (Array.isArray(nested.items)) return nested.items;
442
+ if (Array.isArray(nested.list)) return nested.list;
443
+ if (Array.isArray(nested.content)) return nested.content;
444
+ }
445
+ if (Array.isArray(envelope.records)) return envelope.records;
446
+ if (Array.isArray(envelope.items)) return envelope.items;
447
+ if (Array.isArray(envelope.list)) return envelope.list;
448
+ if (Array.isArray(envelope.content)) return envelope.content;
449
+ }
450
+ return [];
451
+ }
452
+
453
+ // src/resources/api.ts
454
+ function toResourceStatus(value) {
455
+ const n = Number(value);
456
+ return n === RESOURCE_STATUS_ENABLED ? RESOURCE_STATUS_ENABLED : RESOURCE_STATUS_DISABLED;
457
+ }
458
+ function toBoolean(value) {
459
+ if (typeof value === "boolean") return value;
460
+ if (typeof value === "number") return value !== 0;
461
+ if (typeof value === "string") {
462
+ const v = value.trim().toLowerCase();
463
+ return v === "true" || v === "1" || v === "yes" || v === "\u662F";
464
+ }
465
+ return false;
466
+ }
467
+ function mapAuthorizationResource(item) {
468
+ if (!item || typeof item !== "object") return null;
469
+ const row = item;
470
+ const resourceId = row.resourceId ?? row.resource_id ?? row.id;
471
+ if (resourceId === void 0 || resourceId === null || resourceId === "") return null;
472
+ return {
473
+ resourceId: String(resourceId),
474
+ type: RESOURCE_TYPE_API,
475
+ name: String(row.name ?? ""),
476
+ identification: String(row.identification ?? row.identity ?? ""),
477
+ status: toResourceStatus(row.status),
478
+ private: toBoolean(row.private ?? row.isPrivate ?? row.is_private),
479
+ description: String(row.description ?? row.desc ?? "")
480
+ };
481
+ }
482
+ function buildListUrl(params) {
483
+ const parts = [];
484
+ appendQueryParam(parts, "type", RESOURCE_TYPE_API);
485
+ appendQueryParam(parts, "page-token", params?.pagination?.pageToken ?? "");
486
+ appendQueryParam(parts, "page-size", params?.pagination?.pageSize ?? "20");
487
+ appendQueryParam(parts, "page-direction", params?.pagination?.pageDirection ?? "current");
488
+ return `/authorization-resources?${parts.join("&")}`;
489
+ }
490
+ function buildCreateBody(values, resourceId = getAppClientId()) {
491
+ return {
492
+ resourceId,
493
+ type: RESOURCE_TYPE_API,
494
+ name: values.name.trim(),
495
+ identification: values.identification.trim(),
496
+ status: values.status,
497
+ private: values.private,
498
+ description: values.description.trim()
499
+ };
500
+ }
501
+ function buildUpdateBody(values) {
502
+ return {
503
+ type: RESOURCE_TYPE_API,
504
+ name: values.name.trim(),
505
+ identification: values.identification.trim(),
506
+ status: values.status,
507
+ private: values.private,
508
+ description: values.description.trim()
509
+ };
510
+ }
511
+ function createAuthorizationResourceApi(request) {
512
+ return {
513
+ async list(params, signal) {
514
+ const json = await request({
515
+ method: "GET",
516
+ url: buildListUrl(params),
517
+ signal
518
+ });
519
+ const records = extractRecords(json).map(mapAuthorizationResource).filter((item) => item !== null);
520
+ const pagination = extractPagination(json);
521
+ return {
522
+ records,
523
+ ...pagination
524
+ };
525
+ },
526
+ async create(values, signal) {
527
+ return request({
528
+ method: "POST",
529
+ url: "/authorization-resources",
530
+ body: buildCreateBody(values),
531
+ signal
532
+ });
533
+ },
534
+ async update(resourceId, values, signal) {
535
+ return request({
536
+ method: "PATCH",
537
+ url: `/authorization-resources/${encodeURIComponent(resourceId)}`,
538
+ body: buildUpdateBody(values),
539
+ signal
540
+ });
541
+ },
542
+ async remove(resourceId, signal) {
543
+ return request({
544
+ method: "DELETE",
545
+ url: `/authorization-resources/${encodeURIComponent(resourceId)}`,
546
+ signal
547
+ });
548
+ }
549
+ };
550
+ }
551
+ function createDefaultResourceRequest(options = {}) {
552
+ const baseUrl = (options.baseUrl ?? "").replace(/\/+$/, "");
553
+ const credentials = options.credentials ?? "include";
554
+ return async function request({
555
+ method,
556
+ url,
557
+ body,
558
+ signal
559
+ }) {
560
+ const path = url.startsWith("http") ? url : `${baseUrl}${url.startsWith("/") ? url : `/${url}`}`;
561
+ const headers = {
562
+ Accept: "application/json",
563
+ ...await options.getHeaders?.()
564
+ };
565
+ let payload;
566
+ if (body !== void 0) {
567
+ headers["Content-Type"] = "application/json";
568
+ payload = JSON.stringify(body);
569
+ }
570
+ const response = await fetch(path, {
571
+ method,
572
+ headers,
573
+ body: payload,
574
+ credentials,
575
+ signal
576
+ });
577
+ if (!response.ok) {
578
+ const text2 = await response.text().catch(() => "");
579
+ throw new Error(text2 || `HTTP ${response.status}`);
580
+ }
581
+ if (response.status === 204) {
582
+ return void 0;
583
+ }
584
+ const text = await response.text();
585
+ if (!text) return void 0;
586
+ return JSON.parse(text);
587
+ };
588
+ }
589
+
590
+ // src/vue/ResourceManager.ts
214
591
  var PAGE_SIZE_OPTIONS = ["10", "20", "50", "100"];
215
592
  function emptyForm() {
216
593
  return {
@@ -765,33 +1142,14 @@ var ResourceManager = defineComponent2({
765
1142
  ]);
766
1143
  }
767
1144
  });
768
-
769
- // src/vue/index.ts
770
- import { PermissionStore, createPermissionStore as createPermissionStore2 } from "../core";
771
- import { getAppClientId, getDeviceWorkerId, snowyflake } from "../utils/snowflake";
772
- import {
773
- RESOURCE_PRIVATE_OPTIONS as RESOURCE_PRIVATE_OPTIONS2,
774
- RESOURCE_STATUS_DISABLED,
775
- RESOURCE_STATUS_ENABLED as RESOURCE_STATUS_ENABLED2,
776
- RESOURCE_STATUS_OPTIONS as RESOURCE_STATUS_OPTIONS2,
777
- RESOURCE_TYPE_API,
778
- appendQueryParam,
779
- buildCreateBody,
780
- buildUpdateBody,
781
- createAuthorizationResourceApi,
782
- createDefaultResourceRequest,
783
- extractPagination,
784
- extractRecords,
785
- mapAuthorizationResource
786
- } from "../resources";
787
1145
  export {
788
1146
  Can,
789
1147
  PERMISSION_STORE_KEY,
790
1148
  PermissionStore,
791
- RESOURCE_PRIVATE_OPTIONS2 as RESOURCE_PRIVATE_OPTIONS,
1149
+ RESOURCE_PRIVATE_OPTIONS,
792
1150
  RESOURCE_STATUS_DISABLED,
793
- RESOURCE_STATUS_ENABLED2 as RESOURCE_STATUS_ENABLED,
794
- RESOURCE_STATUS_OPTIONS2 as RESOURCE_STATUS_OPTIONS,
1151
+ RESOURCE_STATUS_ENABLED,
1152
+ RESOURCE_STATUS_OPTIONS,
795
1153
  RESOURCE_TYPE_API,
796
1154
  ResourceManager,
797
1155
  appendQueryParam,
@@ -800,7 +1158,7 @@ export {
800
1158
  createAuthorizationResourceApi,
801
1159
  createDefaultResourceRequest,
802
1160
  createPermissionPlugin,
803
- createPermissionStore2 as createPermissionStore,
1161
+ createPermissionStore,
804
1162
  createVPermission,
805
1163
  extractPagination,
806
1164
  extractRecords,