katanakit-js 2.2.1 → 2.12.9
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/README.md +72 -437
- package/dist/adapters/astro/astro.service.d.ts +103 -15
- package/dist/adapters/astro/astro.service.d.ts.map +1 -1
- package/dist/adapters/astro/astro.service.js +145 -75
- package/dist/adapters/astro/astro.service.js.map +1 -1
- package/dist/adapters/astro/index.d.ts +1 -1
- package/dist/adapters/astro/index.d.ts.map +1 -1
- package/dist/adapters/astro/index.js +1 -1
- package/dist/adapters/astro/index.js.map +1 -1
- package/dist/adapters/astro/rss.service.d.ts +85 -105
- package/dist/adapters/astro/rss.service.d.ts.map +1 -1
- package/dist/adapters/astro/rss.service.js +172 -168
- package/dist/adapters/astro/rss.service.js.map +1 -1
- package/dist/adapters/astro/seo.service.d.ts +10 -0
- package/dist/adapters/astro/seo.service.d.ts.map +1 -0
- package/dist/adapters/astro/seo.service.js +3 -0
- package/dist/adapters/astro/seo.service.js.map +1 -0
- package/dist/adapters/express/app.d.ts +30 -1
- package/dist/adapters/express/app.d.ts.map +1 -1
- package/dist/adapters/express/app.js +31 -3
- package/dist/adapters/express/app.js.map +1 -1
- package/dist/adapters/express/index.d.ts +2 -2
- package/dist/adapters/express/index.d.ts.map +1 -1
- package/dist/adapters/express/index.js +2 -2
- package/dist/adapters/express/index.js.map +1 -1
- package/dist/adapters/express/main.js +2 -2
- package/dist/adapters/express/main.js.map +1 -1
- package/dist/adapters/express/products.controller.d.ts +67 -8
- package/dist/adapters/express/products.controller.d.ts.map +1 -1
- package/dist/adapters/express/products.controller.js +105 -49
- package/dist/adapters/express/products.controller.js.map +1 -1
- package/dist/adapters/express/server.d.ts +37 -13
- package/dist/adapters/express/server.d.ts.map +1 -1
- package/dist/adapters/express/server.js +118 -53
- package/dist/adapters/express/server.js.map +1 -1
- package/dist/adapters/nuxt/nuxt.service.d.ts +8 -6
- package/dist/adapters/nuxt/nuxt.service.d.ts.map +1 -1
- package/dist/adapters/nuxt/nuxt.service.js +34 -10
- package/dist/adapters/nuxt/nuxt.service.js.map +1 -1
- package/dist/adapters/vue/vue.service.d.ts +5 -2
- package/dist/adapters/vue/vue.service.d.ts.map +1 -1
- package/dist/adapters/vue/vue.service.js +41 -7
- package/dist/adapters/vue/vue.service.js.map +1 -1
- package/dist/config/index.d.ts +2 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/seo-meta.types.d.ts +177 -0
- package/dist/config/seo-meta.types.d.ts.map +1 -0
- package/dist/config/seo-meta.types.js +11 -0
- package/dist/config/seo-meta.types.js.map +1 -0
- package/dist/config/seo.service.d.ts +41 -58
- package/dist/config/seo.service.d.ts.map +1 -1
- package/dist/config/seo.service.js +468 -136
- package/dist/config/seo.service.js.map +1 -1
- package/dist/config/site.config.d.ts +10 -50
- package/dist/config/site.config.d.ts.map +1 -1
- package/dist/config/site.config.js +8 -36
- package/dist/config/site.config.js.map +1 -1
- package/dist/core/index.d.ts +1 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/services/dates.service.d.ts +149 -22
- package/dist/core/services/dates.service.d.ts.map +1 -1
- package/dist/core/services/dates.service.js +201 -54
- package/dist/core/services/dates.service.js.map +1 -1
- package/dist/core/services/error.service.d.ts +32 -20
- package/dist/core/services/error.service.d.ts.map +1 -1
- package/dist/core/services/error.service.js +44 -32
- package/dist/core/services/error.service.js.map +1 -1
- package/dist/core/services/formatter.service.d.ts +245 -35
- package/dist/core/services/formatter.service.d.ts.map +1 -1
- package/dist/core/services/formatter.service.js +281 -57
- package/dist/core/services/formatter.service.js.map +1 -1
- package/dist/core/services/generator.service.d.ts +115 -26
- package/dist/core/services/generator.service.d.ts.map +1 -1
- package/dist/core/services/generator.service.js +191 -56
- package/dist/core/services/generator.service.js.map +1 -1
- package/dist/core/services/geometry.service.d.ts +369 -39
- package/dist/core/services/geometry.service.d.ts.map +1 -1
- package/dist/core/services/geometry.service.js +424 -66
- package/dist/core/services/geometry.service.js.map +1 -1
- package/dist/core/services/http.service.d.ts +244 -21
- package/dist/core/services/http.service.d.ts.map +1 -1
- package/dist/core/services/http.service.js +419 -98
- package/dist/core/services/http.service.js.map +1 -1
- package/dist/core/services/logger.service.d.ts +95 -29
- package/dist/core/services/logger.service.d.ts.map +1 -1
- package/dist/core/services/logger.service.js +167 -41
- package/dist/core/services/logger.service.js.map +1 -1
- package/dist/core/services/reactive.service.d.ts +146 -19
- package/dist/core/services/reactive.service.d.ts.map +1 -1
- package/dist/core/services/reactive.service.js +278 -137
- package/dist/core/services/reactive.service.js.map +1 -1
- package/dist/core/services/timing.service.d.ts +142 -20
- package/dist/core/services/timing.service.d.ts.map +1 -1
- package/dist/core/services/timing.service.js +324 -185
- package/dist/core/services/timing.service.js.map +1 -1
- package/dist/core/services/utils.service.d.ts +228 -43
- package/dist/core/services/utils.service.d.ts.map +1 -1
- package/dist/core/services/utils.service.js +305 -125
- package/dist/core/services/utils.service.js.map +1 -1
- package/dist/infrastructure/dom/dom.service.d.ts +307 -44
- package/dist/infrastructure/dom/dom.service.d.ts.map +1 -1
- package/dist/infrastructure/dom/dom.service.js +408 -129
- package/dist/infrastructure/dom/dom.service.js.map +1 -1
- package/dist/infrastructure/index.d.ts +0 -3
- package/dist/infrastructure/index.d.ts.map +1 -1
- package/dist/infrastructure/index.js +0 -3
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/infrastructure/observer/observer.service.d.ts +124 -31
- package/dist/infrastructure/observer/observer.service.d.ts.map +1 -1
- package/dist/infrastructure/observer/observer.service.js +227 -131
- package/dist/infrastructure/observer/observer.service.js.map +1 -1
- package/dist/infrastructure/sensors/sensors.service.d.ts +154 -22
- package/dist/infrastructure/sensors/sensors.service.d.ts.map +1 -1
- package/dist/infrastructure/sensors/sensors.service.js +264 -112
- package/dist/infrastructure/sensors/sensors.service.js.map +1 -1
- package/dist/infrastructure/storage/storage.service.d.ts +123 -45
- package/dist/infrastructure/storage/storage.service.d.ts.map +1 -1
- package/dist/infrastructure/storage/storage.service.js +236 -66
- package/dist/infrastructure/storage/storage.service.js.map +1 -1
- package/dist/infrastructure/theme/theme.service.d.ts +93 -29
- package/dist/infrastructure/theme/theme.service.d.ts.map +1 -1
- package/dist/infrastructure/theme/theme.service.js +198 -96
- package/dist/infrastructure/theme/theme.service.js.map +1 -1
- package/dist/infrastructure/viewport/viewport.service.d.ts +233 -35
- package/dist/infrastructure/viewport/viewport.service.d.ts.map +1 -1
- package/dist/infrastructure/viewport/viewport.service.js +358 -139
- package/dist/infrastructure/viewport/viewport.service.js.map +1 -1
- package/dist/infrastructure/worker/worker.service.d.ts +84 -38
- package/dist/infrastructure/worker/worker.service.d.ts.map +1 -1
- package/dist/infrastructure/worker/worker.service.js +234 -133
- package/dist/infrastructure/worker/worker.service.js.map +1 -1
- package/dist/prisma/index.d.ts +2 -0
- package/dist/prisma/index.d.ts.map +1 -0
- package/dist/prisma/index.js +2 -0
- package/dist/prisma/index.js.map +1 -0
- package/dist/prisma/schema.json +11 -33
- package/dist/prisma/use-prisma.d.ts +68 -0
- package/dist/prisma/use-prisma.d.ts.map +1 -0
- package/dist/prisma/use-prisma.js +82 -0
- package/dist/prisma/use-prisma.js.map +1 -0
- package/dist/types/index.d.ts +20 -12
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +124 -125
- package/CHANGELOG.md +0 -101
|
@@ -1,25 +1,157 @@
|
|
|
1
1
|
import type { BatteryManager, GeoPosition } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
3
|
+
* Requests a media stream (camera, microphone, or both).
|
|
4
|
+
*
|
|
5
|
+
* @param constraints - MediaStream constraints (default: video + audio).
|
|
6
|
+
* @returns A `MediaStream` or `null` if the API is unavailable or permission is denied.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const stream = await useGetMediaStream({ video: true, audio: false });
|
|
11
|
+
* if (stream) {
|
|
12
|
+
* videoElement.srcObject = stream;
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function useGetMediaStream(constraints?: MediaStreamConstraints): Promise<MediaStream | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Stops all tracks in a media stream (releases camera/microphone).
|
|
19
|
+
*
|
|
20
|
+
* @param stream - The MediaStream to stop, or `null`.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const stream = await useGetMediaStream();
|
|
25
|
+
* // ... use stream ...
|
|
26
|
+
* useStopMediaStream(stream);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function useStopMediaStream(stream: MediaStream | null): void;
|
|
30
|
+
/**
|
|
31
|
+
* Opens the front-facing (user) camera.
|
|
32
|
+
*
|
|
33
|
+
* @returns A video-only `MediaStream` or `null`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const selfieStream = await useGetFrontCamera();
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function useGetFrontCamera(): Promise<MediaStream | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Opens the back-facing (environment) camera.
|
|
43
|
+
*
|
|
44
|
+
* @returns A video-only `MediaStream` or `null`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const rearStream = await useGetBackCamera();
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function useGetBackCamera(): Promise<MediaStream | null>;
|
|
52
|
+
/**
|
|
53
|
+
* Gets the device's current geographic position once.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Optional PositionOptions to override defaults.
|
|
56
|
+
* @returns A {@link GeoPosition} object or `null` on error / unavailability.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* const pos = await useGetGeolocation({ enableHighAccuracy: true });
|
|
61
|
+
* if (pos) console.log(`${pos.lat}, ${pos.lng}`);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function useGetGeolocation(options?: PositionOptions): Promise<GeoPosition | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Continuously watches the device's geographic position.
|
|
67
|
+
*
|
|
68
|
+
* @param callback - Called with a {@link GeoPosition} on each position update.
|
|
69
|
+
* @param options - Optional PositionOptions to override defaults.
|
|
70
|
+
* @returns A cleanup function that stops watching, or `null` if unavailable.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const stop = useWatchGeolocation((pos) => {
|
|
75
|
+
* console.log("Moved to", pos.lat, pos.lng);
|
|
76
|
+
* });
|
|
77
|
+
* // later:
|
|
78
|
+
* stop?.();
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function useWatchGeolocation(callback: (position: GeoPosition) => void, options?: PositionOptions): (() => void) | null;
|
|
82
|
+
/**
|
|
83
|
+
* Requests permission to access device orientation/motion sensors (required on iOS 13+).
|
|
84
|
+
*
|
|
85
|
+
* @returns `true` if permission is granted or already available, `false` otherwise.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const granted = await useRequestMotionPermission();
|
|
90
|
+
* if (granted) {
|
|
91
|
+
* useOnDeviceOrientation((e) => console.log(e.alpha, e.beta));
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function useRequestMotionPermission(): Promise<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* Listens for device orientation events (compass heading, tilt).
|
|
98
|
+
*
|
|
99
|
+
* @param callback - Called with each `DeviceOrientationEvent`.
|
|
100
|
+
* @returns A cleanup function that removes the listener, or `null` if unavailable.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* const off = useOnDeviceOrientation((e) => {
|
|
105
|
+
* console.log("Alpha:", e.alpha);
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export declare function useOnDeviceOrientation(callback: (event: DeviceOrientationEvent) => void): (() => void) | null;
|
|
110
|
+
/**
|
|
111
|
+
* Listens for device motion events (acceleration, rotation rate).
|
|
112
|
+
*
|
|
113
|
+
* @param callback - Called with each `DeviceMotionEvent`.
|
|
114
|
+
* @returns A cleanup function that removes the listener, or `null` if unavailable.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* const off = useOnDeviceMotion((e) => {
|
|
119
|
+
* console.log("Acceleration:", e.acceleration);
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare function useOnDeviceMotion(callback: (event: DeviceMotionEvent) => void): (() => void) | null;
|
|
124
|
+
/**
|
|
125
|
+
* Triggers the device vibration motor with a given pattern.
|
|
126
|
+
*
|
|
127
|
+
* @param pattern - A single duration (ms) or an array of vibrate/pause durations.
|
|
128
|
+
* @returns `true` if vibration was triggered, `false` otherwise.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* useVibrate(200); // vibrate 200 ms
|
|
133
|
+
* useVibrate([100, 50, 100]); // vibrate, pause, vibrate
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare function useVibrate(pattern: number | number[]): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Stops any ongoing vibration.
|
|
139
|
+
*
|
|
140
|
+
* @returns `true` if the call succeeded.
|
|
141
|
+
*/
|
|
142
|
+
export declare function useStopVibration(): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Gets the device battery status.
|
|
145
|
+
*
|
|
146
|
+
* @returns A `BatteryManager` object or `null` if the API is unavailable.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* const battery = await useGetBattery();
|
|
151
|
+
* if (battery) {
|
|
152
|
+
* console.log(`${Math.round(battery.level * 100)}%`);
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare function useGetBattery(): Promise<BatteryManager | null>;
|
|
25
157
|
//# sourceMappingURL=sensors.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sensors.service.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/sensors/sensors.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"sensors.service.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/sensors/sensors.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAmBxE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACtC,WAAW,GAAE,sBAAqD,GAChE,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAY7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAMnE;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAErE;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAEpE;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmB9F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,EACzC,OAAO,CAAC,EAAE,eAAe,GACvB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAkBrB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,OAAO,CAAC,CAsBnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,GAC/C,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAQrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC1C,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAQrB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAK9D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAepE"}
|
|
@@ -1,133 +1,285 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useLogger } from "../../core/services/logger.service.js";
|
|
2
|
+
// ============================================================
|
|
3
|
+
// Internal helpers
|
|
4
|
+
// ============================================================
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
6
|
+
* Checks whether the code is running in a browser environment with `navigator`.
|
|
7
|
+
*
|
|
8
|
+
* @returns `true` if both `window` and `navigator` are defined.
|
|
5
9
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
function isBrowser() {
|
|
11
|
+
return typeof window !== "undefined" && typeof navigator !== "undefined";
|
|
12
|
+
}
|
|
13
|
+
// ============================================================
|
|
14
|
+
// Media (camera / microphone)
|
|
15
|
+
// ============================================================
|
|
16
|
+
/**
|
|
17
|
+
* Requests a media stream (camera, microphone, or both).
|
|
18
|
+
*
|
|
19
|
+
* @param constraints - MediaStream constraints (default: video + audio).
|
|
20
|
+
* @returns A `MediaStream` or `null` if the API is unavailable or permission is denied.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const stream = await useGetMediaStream({ video: true, audio: false });
|
|
25
|
+
* if (stream) {
|
|
26
|
+
* videoElement.srcObject = stream;
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export async function useGetMediaStream(constraints = { video: true, audio: true }) {
|
|
31
|
+
if (!isBrowser() || !navigator.mediaDevices?.getUserMedia) {
|
|
32
|
+
useLogger("warn", "[getMediaStream] API not supported in this environment.");
|
|
33
|
+
return null;
|
|
14
34
|
}
|
|
15
|
-
|
|
16
|
-
return
|
|
35
|
+
try {
|
|
36
|
+
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
17
37
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
useLog("error", "[getMediaStream] Permission denied or error:", error);
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
useLogger("error", "[getMediaStream] Permission denied or error:", error);
|
|
40
|
+
return null;
|
|
30
41
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Stops all tracks in a media stream (releases camera/microphone).
|
|
45
|
+
*
|
|
46
|
+
* @param stream - The MediaStream to stop, or `null`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const stream = await useGetMediaStream();
|
|
51
|
+
* // ... use stream ...
|
|
52
|
+
* useStopMediaStream(stream);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function useStopMediaStream(stream) {
|
|
56
|
+
if (stream) {
|
|
57
|
+
for (const track of stream.getTracks()) {
|
|
58
|
+
track.stop();
|
|
36
59
|
}
|
|
37
60
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Opens the front-facing (user) camera.
|
|
64
|
+
*
|
|
65
|
+
* @returns A video-only `MediaStream` or `null`.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const selfieStream = await useGetFrontCamera();
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export async function useGetFrontCamera() {
|
|
73
|
+
return useGetMediaStream({ video: { facingMode: "user" }, audio: false });
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Opens the back-facing (environment) camera.
|
|
77
|
+
*
|
|
78
|
+
* @returns A video-only `MediaStream` or `null`.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const rearStream = await useGetBackCamera();
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export async function useGetBackCamera() {
|
|
86
|
+
return useGetMediaStream({ video: { facingMode: "environment" }, audio: false });
|
|
87
|
+
}
|
|
88
|
+
// ============================================================
|
|
89
|
+
// Geolocation
|
|
90
|
+
// ============================================================
|
|
91
|
+
/**
|
|
92
|
+
* Gets the device's current geographic position once.
|
|
93
|
+
*
|
|
94
|
+
* @param options - Optional PositionOptions to override defaults.
|
|
95
|
+
* @returns A {@link GeoPosition} object or `null` on error / unavailability.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const pos = await useGetGeolocation({ enableHighAccuracy: true });
|
|
100
|
+
* if (pos) console.log(`${pos.lat}, ${pos.lng}`);
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export async function useGetGeolocation(options) {
|
|
104
|
+
if (!isBrowser() || !navigator.geolocation)
|
|
105
|
+
return null;
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
navigator.geolocation.getCurrentPosition((position) => {
|
|
108
|
+
resolve({
|
|
65
109
|
lat: position.coords.latitude,
|
|
66
110
|
lng: position.coords.longitude,
|
|
67
111
|
accuracy: position.coords.accuracy,
|
|
68
112
|
});
|
|
69
113
|
}, (error) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
useLogger("error", "[getGeolocation] Error:", error.message);
|
|
115
|
+
resolve(null);
|
|
116
|
+
}, { enableHighAccuracy: true, timeout: 10000, ...options });
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Continuously watches the device's geographic position.
|
|
121
|
+
*
|
|
122
|
+
* @param callback - Called with a {@link GeoPosition} on each position update.
|
|
123
|
+
* @param options - Optional PositionOptions to override defaults.
|
|
124
|
+
* @returns A cleanup function that stops watching, or `null` if unavailable.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* const stop = useWatchGeolocation((pos) => {
|
|
129
|
+
* console.log("Moved to", pos.lat, pos.lng);
|
|
130
|
+
* });
|
|
131
|
+
* // later:
|
|
132
|
+
* stop?.();
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function useWatchGeolocation(callback, options) {
|
|
136
|
+
if (!isBrowser() || !navigator.geolocation)
|
|
137
|
+
return null;
|
|
138
|
+
const watchId = navigator.geolocation.watchPosition((position) => {
|
|
139
|
+
callback({
|
|
140
|
+
lat: position.coords.latitude,
|
|
141
|
+
lng: position.coords.longitude,
|
|
142
|
+
accuracy: position.coords.accuracy,
|
|
143
|
+
});
|
|
144
|
+
}, (error) => {
|
|
145
|
+
useLogger("error", "[watchGeolocation] Error:", error.message);
|
|
146
|
+
}, { enableHighAccuracy: true, ...options });
|
|
147
|
+
return () => navigator.geolocation.clearWatch(watchId);
|
|
148
|
+
}
|
|
149
|
+
// ============================================================
|
|
150
|
+
// Device motion / orientation
|
|
151
|
+
// ============================================================
|
|
152
|
+
/**
|
|
153
|
+
* Requests permission to access device orientation/motion sensors (required on iOS 13+).
|
|
154
|
+
*
|
|
155
|
+
* @returns `true` if permission is granted or already available, `false` otherwise.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* const granted = await useRequestMotionPermission();
|
|
160
|
+
* if (granted) {
|
|
161
|
+
* useOnDeviceOrientation((e) => console.log(e.alpha, e.beta));
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export async function useRequestMotionPermission() {
|
|
166
|
+
if (!isBrowser())
|
|
167
|
+
return false;
|
|
168
|
+
if (typeof DeviceOrientationEvent === "undefined") {
|
|
111
169
|
return false;
|
|
112
170
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
async useGetBattery() {
|
|
117
|
-
if (!this.isBrowser())
|
|
118
|
-
return null;
|
|
119
|
-
const nav = navigator;
|
|
120
|
-
if (!nav.getBattery)
|
|
121
|
-
return null;
|
|
171
|
+
const DeviceOrientationEventExtended = DeviceOrientationEvent;
|
|
172
|
+
if (typeof DeviceOrientationEventExtended.requestPermission === "function") {
|
|
122
173
|
try {
|
|
123
|
-
|
|
174
|
+
const response = await DeviceOrientationEventExtended.requestPermission();
|
|
175
|
+
return response === "granted";
|
|
124
176
|
}
|
|
125
177
|
catch (error) {
|
|
126
|
-
|
|
127
|
-
return
|
|
178
|
+
useLogger("error", "[requestMotionPermission] Error:", error);
|
|
179
|
+
return false;
|
|
128
180
|
}
|
|
129
181
|
}
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Listens for device orientation events (compass heading, tilt).
|
|
186
|
+
*
|
|
187
|
+
* @param callback - Called with each `DeviceOrientationEvent`.
|
|
188
|
+
* @returns A cleanup function that removes the listener, or `null` if unavailable.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* const off = useOnDeviceOrientation((e) => {
|
|
193
|
+
* console.log("Alpha:", e.alpha);
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export function useOnDeviceOrientation(callback) {
|
|
198
|
+
if (!isBrowser() || typeof DeviceOrientationEvent === "undefined")
|
|
199
|
+
return null;
|
|
200
|
+
window.addEventListener("deviceorientation", callback);
|
|
201
|
+
return () => {
|
|
202
|
+
window.removeEventListener("deviceorientation", callback);
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Listens for device motion events (acceleration, rotation rate).
|
|
207
|
+
*
|
|
208
|
+
* @param callback - Called with each `DeviceMotionEvent`.
|
|
209
|
+
* @returns A cleanup function that removes the listener, or `null` if unavailable.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* const off = useOnDeviceMotion((e) => {
|
|
214
|
+
* console.log("Acceleration:", e.acceleration);
|
|
215
|
+
* });
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export function useOnDeviceMotion(callback) {
|
|
219
|
+
if (!isBrowser())
|
|
220
|
+
return null;
|
|
221
|
+
window.addEventListener("devicemotion", callback);
|
|
222
|
+
return () => {
|
|
223
|
+
window.removeEventListener("devicemotion", callback);
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
// ============================================================
|
|
227
|
+
// Vibration
|
|
228
|
+
// ============================================================
|
|
229
|
+
/**
|
|
230
|
+
* Triggers the device vibration motor with a given pattern.
|
|
231
|
+
*
|
|
232
|
+
* @param pattern - A single duration (ms) or an array of vibrate/pause durations.
|
|
233
|
+
* @returns `true` if vibration was triggered, `false` otherwise.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* useVibrate(200); // vibrate 200 ms
|
|
238
|
+
* useVibrate([100, 50, 100]); // vibrate, pause, vibrate
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
export function useVibrate(pattern) {
|
|
242
|
+
if (isBrowser() && "vibrate" in navigator) {
|
|
243
|
+
return navigator.vibrate(pattern);
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Stops any ongoing vibration.
|
|
249
|
+
*
|
|
250
|
+
* @returns `true` if the call succeeded.
|
|
251
|
+
*/
|
|
252
|
+
export function useStopVibration() {
|
|
253
|
+
return useVibrate(0);
|
|
254
|
+
}
|
|
255
|
+
// ============================================================
|
|
256
|
+
// Battery
|
|
257
|
+
// ============================================================
|
|
258
|
+
/**
|
|
259
|
+
* Gets the device battery status.
|
|
260
|
+
*
|
|
261
|
+
* @returns A `BatteryManager` object or `null` if the API is unavailable.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```ts
|
|
265
|
+
* const battery = await useGetBattery();
|
|
266
|
+
* if (battery) {
|
|
267
|
+
* console.log(`${Math.round(battery.level * 100)}%`);
|
|
268
|
+
* }
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
export async function useGetBattery() {
|
|
272
|
+
if (!isBrowser())
|
|
273
|
+
return null;
|
|
274
|
+
const nav = navigator;
|
|
275
|
+
if (!nav.getBattery)
|
|
276
|
+
return null;
|
|
277
|
+
try {
|
|
278
|
+
return await nav.getBattery();
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
useLogger("error", "[getBattery] Error:", error);
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
130
284
|
}
|
|
131
|
-
// Singleton instance export.
|
|
132
|
-
export const sensorsUtils = SensorsUtils.getInstance();
|
|
133
285
|
//# sourceMappingURL=sensors.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sensors.service.js","sourceRoot":"","sources":["../../../src/infrastructure/sensors/sensors.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sensors.service.js","sourceRoot":"","sources":["../../../src/infrastructure/sensors/sensors.service.ts"],"names":[],"mappings":"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"}
|