nuxt-cap 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gabriel 'DethDKN' Rosa <https://github.com/dethdkn>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,218 @@
1
+ <h1 align="center">nuxt-cap</h1>
2
+ <p align="center">๐Ÿงข Integrate Cap into your Nuxt websites/applications.</p>
3
+
4
+ <p align="center">
5
+ <a href="https://rosa.dev.br">
6
+ <img src="https://img.shields.io/badge/check me!-๐Ÿ‘ป-F28AA9" alt="rosa.dev.br"/>
7
+ </a>
8
+ <a href="https://github.com/dethdkn/nuxt-cap/blob/main/LICENSE">
9
+ <img src="https://img.shields.io/github/license/dethdkn/nuxt-cap?color=%233da639&logo=open%20source%20initiative" alt="License"/>
10
+ </a>
11
+ <a href="https://gitmoji.dev">
12
+ <img src="https://img.shields.io/badge/gitmoji-%20๐Ÿ˜œ%20๐Ÿ˜-FFDD67" alt="Gitmoji"/>
13
+ </a>
14
+ </p>
15
+
16
+ ## ๐Ÿš€ Setup
17
+
18
+ Install `nuxt-cap` dependency to your project:
19
+
20
+ ```sh
21
+ npx nuxt module add nuxt-cap
22
+ ```
23
+
24
+ ## โš™๏ธ Configuration
25
+
26
+ You can configure **nuxt-cap** in two ways:
27
+
28
+ ### 1๏ธโƒฃ Using `nuxt.config.ts`
29
+
30
+ Set the `apiEndpoint` directly in your Nuxt configuration:
31
+
32
+ ```ts
33
+ export default defineNuxtConfig({
34
+ cap: {
35
+ apiEndpoint: 'https://cap.example.com/<KEY>/',
36
+ },
37
+ })
38
+ ```
39
+
40
+ ---
41
+
42
+ ### 2๏ธโƒฃ Using an Environment Variable (Recommended)
43
+
44
+ ```bash
45
+ NUXT_PUBLIC_CAP_API_ENDPOINT="https://cap.example.com/<KEY>/"
46
+ ```
47
+
48
+ Because this uses **Nuxt runtimeConfig**, it supports runtime environment variables โ€” meaning you can change the endpoint **after build time** without rebuilding your application.
49
+
50
+ ## ๐Ÿงฉ `<Cap />` Component
51
+
52
+ This module auto-imports a component called:
53
+
54
+ ```vue
55
+ <Cap />
56
+ ```
57
+
58
+ ---
59
+
60
+ ## ๐Ÿ“ก Emits
61
+
62
+ The component exposes four events:
63
+
64
+ - `@solve`
65
+ - `@error`
66
+ - `@reset`
67
+ - `@progress`
68
+
69
+ ### Example
70
+
71
+ ```vue
72
+ <script setup lang="ts">
73
+ import type {
74
+ CapErrorEvent,
75
+ CapProgressEvent,
76
+ CapResetEvent,
77
+ CapSolveEvent,
78
+ } from '@cap.js/widget'
79
+
80
+ function onSolve(event: CapSolveEvent): void {
81
+ console.log('Solved:', event)
82
+ }
83
+
84
+ function onError(event: CapErrorEvent): void {
85
+ console.error('Error:', event)
86
+ }
87
+
88
+ function onReset(event: CapResetEvent): void {
89
+ console.log('Reset:', event)
90
+ }
91
+
92
+ function onProgress(event: CapProgressEvent): void {
93
+ console.log('Progress:', event)
94
+ }
95
+ </script>
96
+
97
+ <template>
98
+ <Cap @solve="onSolve" @error="onError" @reset="onReset" @progress="onProgress" />
99
+ </template>
100
+ ```
101
+
102
+ ## ๐Ÿงฑ Props
103
+
104
+ ### `workerCount?: number`
105
+
106
+ Optional.
107
+
108
+ Defines how many Web Workers Cap should use to solve the proof-of-work challenge.
109
+
110
+ If not set, Cap defaults to:
111
+
112
+ ```ts
113
+ navigator.hardwareConcurrency || 8
114
+ ```
115
+
116
+ ---
117
+
118
+ ### `i18n?: object`
119
+
120
+ Optional.
121
+
122
+ Allows you to customize the widget language.
123
+
124
+ ```ts
125
+ {
126
+ verifyingLabel?: string
127
+ initialState?: string
128
+ solvedLabel?: string
129
+ errorLabel?: string
130
+ wasmDisabled?: string
131
+ verifyAriaLabel?: string
132
+ verifyingAriaLabel?: string
133
+ verifiedAriaLabel?: string
134
+ errorAriaLabel?: string
135
+ }
136
+ ```
137
+
138
+ ### Example
139
+
140
+ ```vue
141
+ <template>
142
+ <Cap
143
+ :worker-count="4"
144
+ :i18n="{
145
+ verifyingLabel: 'Verificando...',
146
+ solvedLabel: 'Verificado',
147
+ errorLabel: 'Erro',
148
+ }" />
149
+ </template>
150
+ ```
151
+
152
+ ## ๐ŸŽจ Customizing Appearance
153
+
154
+ To customize Capโ€™s appearance, follow the official Cap widget customization guide:
155
+ [Customizing](https://capjs.js.org/guide/widget.html#customizing)
156
+
157
+ ## ๐Ÿ”„ Reset
158
+
159
+ To reset the Cap widget programmatically, you can use the provided helper function:
160
+
161
+ ```ts
162
+ resetCap()
163
+ ```
164
+
165
+ ### Example
166
+
167
+ ```vue
168
+ <script setup lang="ts">
169
+ function handleReset(): void {
170
+ // ...anything
171
+ resetCap()
172
+ }
173
+ </script>
174
+
175
+ <template>
176
+ <button @click="handleReset">Reset Cap</button>
177
+
178
+ <Cap />
179
+ </template>
180
+ ```
181
+
182
+ Calling `resetCap()` will reset the current widget state, allowing the challenge to be solved again.
183
+
184
+ ## ๐Ÿ‘ป Invisible Mode
185
+
186
+ For invisible mode, you can use the `useCap()` composable.
187
+
188
+ It returns a Cap instance, similar to the one described in the official invisible guide:
189
+
190
+ [Guide](https://capjs.js.org/guide/invisible.html)
191
+
192
+ You can call any available Cap instance method, such as `cap.solve()`.
193
+
194
+ ### Example
195
+
196
+ ```vue
197
+ <script setup lang="ts">
198
+ const cap = useCap()
199
+
200
+ async function testCap(): Promise<void> {
201
+ if (!cap) return
202
+
203
+ const { token } = await cap.solve()
204
+ console.log(token)
205
+ }
206
+ </script>
207
+
208
+ <template>
209
+ <button @click="testCap">Solve Invisible Cap</button>
210
+ </template>
211
+ ```
212
+
213
+ This allows you to manually trigger the proof-of-work challenge without rendering the `<Cap />` checkbox widget.
214
+
215
+ ## ๐Ÿ“ License
216
+
217
+ Copyright ยฉ 2026 [Gabriel 'DethDKN' Rosa](https://github.com/dethdkn)\
218
+ This project is under [MIT license](https://github.com/dethdkn/nuxt-cap/blob/main/LICENSE)
@@ -0,0 +1,16 @@
1
+ import { NuxtModule } from '@nuxt/schema';
2
+
3
+ declare module 'nuxt/schema' {
4
+ interface PublicRuntimeConfig {
5
+ cap?: {
6
+ apiEndpoint?: string;
7
+ };
8
+ }
9
+ }
10
+ interface ModuleOptions {
11
+ apiEndpoint?: string;
12
+ }
13
+ declare const module$1: NuxtModule<ModuleOptions>;
14
+
15
+ export { module$1 as default };
16
+ export type { ModuleOptions };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "cap",
3
+ "configKey": "cap",
4
+ "compatibility": {
5
+ "nuxt": ">=3.0.0"
6
+ },
7
+ "version": "0.0.0",
8
+ "builder": {
9
+ "@nuxt/module-builder": "1.0.2",
10
+ "unbuild": "3.6.1"
11
+ }
12
+ }
@@ -0,0 +1,22 @@
1
+ import { defineNuxtModule, createResolver, addPlugin, addImports, addComponent } from '@nuxt/kit';
2
+
3
+ const module$1 = defineNuxtModule({
4
+ meta: { name: "cap", configKey: "cap", compatibility: { nuxt: ">=3.0.0" } },
5
+ setup({ apiEndpoint }, nuxt) {
6
+ const resolver = createResolver(import.meta.url);
7
+ const { runtimeConfig } = nuxt.options;
8
+ runtimeConfig.public.cap ??= {};
9
+ runtimeConfig.public.cap.apiEndpoint ??= apiEndpoint ?? "";
10
+ addPlugin({ src: resolver.resolve("./runtime/plugins/cap"), mode: "client" });
11
+ addImports([
12
+ { name: "useCap", from: resolver.resolve("./runtime/composables/useCap") },
13
+ { name: "resetCap", from: resolver.resolve("./runtime/utils/resetCap") }
14
+ ]);
15
+ addComponent({
16
+ name: "Cap",
17
+ filePath: resolver.resolve("./runtime/components/Cap.vue")
18
+ });
19
+ }
20
+ });
21
+
22
+ export { module$1 as default };
@@ -0,0 +1,53 @@
1
+ import type { PropType } from 'vue';
2
+ import type { CapErrorEvent, CapProgressEvent, CapResetEvent, CapSolveEvent } from '@cap.js/widget';
3
+ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
4
+ workerCount: {
5
+ type: NumberConstructor;
6
+ required: false;
7
+ };
8
+ i18n: {
9
+ type: PropType<{
10
+ verifyingLabel?: string;
11
+ initialState?: string;
12
+ solvedLabel?: string;
13
+ errorLabel?: string;
14
+ wasmDisabled?: string;
15
+ verifyAriaLabel?: string;
16
+ verifyingAriaLabel?: string;
17
+ verifiedAriaLabel?: string;
18
+ errorAriaLabel?: string;
19
+ }>;
20
+ required: false;
21
+ };
22
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
23
+ solve: (cap: CapSolveEvent) => any;
24
+ error: (cap: CapErrorEvent) => any;
25
+ reset: (cap: CapResetEvent) => any;
26
+ progress: (cap: CapProgressEvent) => any;
27
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
28
+ workerCount: {
29
+ type: NumberConstructor;
30
+ required: false;
31
+ };
32
+ i18n: {
33
+ type: PropType<{
34
+ verifyingLabel?: string;
35
+ initialState?: string;
36
+ solvedLabel?: string;
37
+ errorLabel?: string;
38
+ wasmDisabled?: string;
39
+ verifyAriaLabel?: string;
40
+ verifyingAriaLabel?: string;
41
+ verifiedAriaLabel?: string;
42
+ errorAriaLabel?: string;
43
+ }>;
44
+ required: false;
45
+ };
46
+ }>> & Readonly<{
47
+ onSolve?: ((cap: CapSolveEvent) => any) | undefined;
48
+ onError?: ((cap: CapErrorEvent) => any) | undefined;
49
+ onReset?: ((cap: CapResetEvent) => any) | undefined;
50
+ onProgress?: ((cap: CapProgressEvent) => any) | undefined;
51
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
52
+ declare const _default: typeof __VLS_export;
53
+ export default _default;
@@ -0,0 +1,60 @@
1
+ <script setup>
2
+ import { onNuxtReady, useRuntimeConfig } from "#app";
3
+ import { onUnmounted, ref } from "vue";
4
+ const props = defineProps({
5
+ workerCount: { type: Number, required: false },
6
+ i18n: {
7
+ type: Object,
8
+ required: false
9
+ }
10
+ });
11
+ const emit = defineEmits(["solve", "error", "reset", "progress"]);
12
+ const capEl = ref();
13
+ function solve(event) {
14
+ emit("solve", event);
15
+ }
16
+ function error(event) {
17
+ emit("error", event);
18
+ }
19
+ function reset(event) {
20
+ emit("reset", event);
21
+ }
22
+ function progress(event) {
23
+ emit("progress", event);
24
+ }
25
+ onNuxtReady(() => {
26
+ const el = capEl.value;
27
+ if (!el) return;
28
+ el.addEventListener("solve", solve);
29
+ el.addEventListener("error", error);
30
+ el.addEventListener("reset", reset);
31
+ el.addEventListener("progress", progress);
32
+ });
33
+ onUnmounted(() => {
34
+ const el = capEl.value;
35
+ if (!el) return;
36
+ el.removeEventListener("solve", solve);
37
+ el.removeEventListener("error", error);
38
+ el.removeEventListener("reset", reset);
39
+ el.removeEventListener("progress", progress);
40
+ });
41
+ const { cap } = useRuntimeConfig().public;
42
+ </script>
43
+
44
+ <template>
45
+ <component
46
+ is="cap-widget"
47
+ ref="capEl"
48
+ id="cap"
49
+ :data-cap-api-endpoint="cap?.apiEndpoint"
50
+ :data-cap-worker-count="workerCount"
51
+ :data-cap-i18n-verifying-label="i18n?.verifyingLabel"
52
+ :data-cap-i18n-initial-state="i18n?.initialState"
53
+ :data-cap-i18n-solved-label="i18n?.solvedLabel"
54
+ :data-cap-i18n-error-label="i18n?.errorLabel"
55
+ :data-cap-i18n-wasm-disabled="i18n?.wasmDisabled"
56
+ :data-cap-verify-aria-label="i18n?.verifyAriaLabel"
57
+ :data-cap-verifying-aria-label="i18n?.verifyingAriaLabel"
58
+ :data-cap-verified-aria-label="i18n?.verifiedAriaLabel"
59
+ :data-cap-error-aria-label="i18n?.errorAriaLabel" />
60
+ </template>
@@ -0,0 +1,53 @@
1
+ import type { PropType } from 'vue';
2
+ import type { CapErrorEvent, CapProgressEvent, CapResetEvent, CapSolveEvent } from '@cap.js/widget';
3
+ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
4
+ workerCount: {
5
+ type: NumberConstructor;
6
+ required: false;
7
+ };
8
+ i18n: {
9
+ type: PropType<{
10
+ verifyingLabel?: string;
11
+ initialState?: string;
12
+ solvedLabel?: string;
13
+ errorLabel?: string;
14
+ wasmDisabled?: string;
15
+ verifyAriaLabel?: string;
16
+ verifyingAriaLabel?: string;
17
+ verifiedAriaLabel?: string;
18
+ errorAriaLabel?: string;
19
+ }>;
20
+ required: false;
21
+ };
22
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
23
+ solve: (cap: CapSolveEvent) => any;
24
+ error: (cap: CapErrorEvent) => any;
25
+ reset: (cap: CapResetEvent) => any;
26
+ progress: (cap: CapProgressEvent) => any;
27
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
28
+ workerCount: {
29
+ type: NumberConstructor;
30
+ required: false;
31
+ };
32
+ i18n: {
33
+ type: PropType<{
34
+ verifyingLabel?: string;
35
+ initialState?: string;
36
+ solvedLabel?: string;
37
+ errorLabel?: string;
38
+ wasmDisabled?: string;
39
+ verifyAriaLabel?: string;
40
+ verifyingAriaLabel?: string;
41
+ verifiedAriaLabel?: string;
42
+ errorAriaLabel?: string;
43
+ }>;
44
+ required: false;
45
+ };
46
+ }>> & Readonly<{
47
+ onSolve?: ((cap: CapSolveEvent) => any) | undefined;
48
+ onError?: ((cap: CapErrorEvent) => any) | undefined;
49
+ onReset?: ((cap: CapResetEvent) => any) | undefined;
50
+ onProgress?: ((cap: CapProgressEvent) => any) | undefined;
51
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
52
+ declare const _default: typeof __VLS_export;
53
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import type { Cap, CapConfig, CapWidget } from '@cap.js/widget';
2
+ export declare function useCap(config?: CapConfig, el?: CapWidget): Cap | undefined;
@@ -0,0 +1,8 @@
1
+ import { useNuxtApp, useRuntimeConfig } from "#app";
2
+ export function useCap(config, el) {
3
+ if (!import.meta.client) return;
4
+ const { $cap } = useNuxtApp();
5
+ const { cap } = useRuntimeConfig().public;
6
+ const capInstance = new $cap({ apiEndpoint: cap?.apiEndpoint, ...config }, el);
7
+ return capInstance;
8
+ }
@@ -0,0 +1,7 @@
1
+ import Cap from '@cap.js/widget';
2
+ declare const _default: import("nuxt/app").Plugin<{
3
+ cap: typeof Cap;
4
+ }> & import("nuxt/app").ObjectPlugin<{
5
+ cap: typeof Cap;
6
+ }>;
7
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import { defineNuxtPlugin } from "#imports";
2
+ import Cap from "@cap.js/widget";
3
+ export default defineNuxtPlugin(() => ({
4
+ provide: {
5
+ cap: Cap
6
+ }
7
+ }));
@@ -0,0 +1 @@
1
+ export declare function resetCap(): void;
@@ -0,0 +1,5 @@
1
+ export function resetCap() {
2
+ if (!import.meta.client) return;
3
+ const cap = document.querySelector("#cap");
4
+ cap?.reset();
5
+ }
@@ -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,69 @@
1
+ {
2
+ "name": "nuxt-cap",
3
+ "version": "0.1.0",
4
+ "description": "๐Ÿงข Integrate Cap into your Nuxt websites/applications.",
5
+ "keywords": [
6
+ "cbpf",
7
+ "module",
8
+ "nuxt"
9
+ ],
10
+ "homepage": "https://github.com/dethdkn/nuxt-cap",
11
+ "bugs": "https://github.com/dethdkn/nuxt-cap/issues",
12
+ "license": "MIT",
13
+ "author": {
14
+ "name": "Gabriel 'DethDKN' Rosa",
15
+ "email": "gabriel@rosa.dev.br",
16
+ "url": "https://rosa.dev.br"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/dethdkn/nuxt-cap.git"
21
+ },
22
+ "funding": "https://github.com/sponsors/dethdkn",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "type": "module",
27
+ "main": "./dist/module.mjs",
28
+ "typesVersions": {
29
+ "*": {
30
+ ".": [
31
+ "./dist/types.d.mts"
32
+ ]
33
+ }
34
+ },
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/types.d.mts",
38
+ "import": "./dist/module.mjs"
39
+ }
40
+ },
41
+ "scripts": {
42
+ "postinstall": "bun run dev:prepare",
43
+ "dev": "nuxi dev playground",
44
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
45
+ "dev:build": "nuxi build playground",
46
+ "build": "nuxt-module-build build",
47
+ "fmt": "oxfmt --check",
48
+ "fmt:fix": "oxfmt",
49
+ "lint": "oxlint --type-aware",
50
+ "lint:fix": "oxlint --type-aware --fix",
51
+ "typecheck": "vue-tsc --noEmit",
52
+ "prerelease": "bun run fmt && bun run lint && bun run typecheck ",
53
+ "release": "bun run prerelease && bun run build && bumpp && sudo npm publish"
54
+ },
55
+ "dependencies": {
56
+ "@cap.js/widget": "^0.1.34",
57
+ "@nuxt/kit": "^4.3.1"
58
+ },
59
+ "devDependencies": {
60
+ "@dethdkn/ox-config": "^1.0.10",
61
+ "@nuxt/module-builder": "^1.0.2",
62
+ "@nuxt/schema": "^4.3.1",
63
+ "@types/bun": "^1.3.9",
64
+ "bumpp": "^10.4.1",
65
+ "nuxt": "^4.3.1",
66
+ "typescript": "5.9.3",
67
+ "vue-tsc": "^3.2.4"
68
+ }
69
+ }