@nawa-captcha/svelte 0.0.0-stage โ†’ 0.1.1

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 CHANGED
@@ -1,3 +1,43 @@
1
- # Temporary Holding Version
1
+ # @nawa-captcha/svelte
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **Nawa Captcha** โ€” a self-hosted, privacy-friendly and accessible puzzle CAPTCHA. A drop-in alternative to reCAPTCHA, hCaptcha and Turnstile with no third-party tracking: your server issues the challenge and verifies the answer.
4
+
5
+ This package: Svelte 5 component.
6
+
7
+ - ๐Ÿงฉ 38 challenge types you choose from (one, two or many, per action): slider jigsaws, rotate, drag to the shadow, jigsaw, hold, icon/colour/clock/symmetry grids, match pairs, tap in order, spell, order and story tiles, connect the dots, maze, math, dice, invisible proof-of-work, an accessible text question and an audio challenge โ€” [see them live](https://oriebalzyuot96.github.io/nawa-captcha/#playground)
8
+ - ๐Ÿ”’ Answers are sealed (AES-256-GCM) and never reach the browser; pass tokens are signed and single-use
9
+ - โ™ฟ Keyboard, touch and screen-reader friendly (text question and audio challenge); Arabic and English; RTL
10
+ - ๐ŸŽจ Premium 3D design, six themes in light and dark plus high contrast (WCAG 2.2 AA), Pelagic UI tokens, optional sound effects
11
+ - ๐Ÿ–ฅ๏ธ Backends: Node.js / Express and ASP.NET Core (`NawaCaptcha.AspNetCore`, coming to NuGet)
12
+
13
+ ## Install
14
+
15
+ > **Coming to npm.** `@nawa-captcha/svelte` is published once the `@nawa-captcha` npm organisation exists. Until then, build it from the [repository](https://github.com/oriebalzyuot96/nawa-captcha) (`npm install && npm run build`, then `npm pack -w @nawa-captcha/svelte`).
16
+
17
+ ```bash
18
+ npm i @nawa-captcha/svelte
19
+ # or
20
+ yarn add @nawa-captcha/svelte
21
+ # or
22
+ pnpm add @nawa-captcha/svelte
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```svelte
28
+ <script lang="ts">
29
+ import { NawaCaptcha } from '@nawa-captcha/svelte';
30
+ let token = $state('');
31
+ </script>
32
+
33
+ <NawaCaptcha bind:token siteKey="main" action="login" lang="en" />
34
+ <button disabled={!token}>Sign in</button>
35
+ ```
36
+
37
+ `types` narrows the server's allowed puzzles: `<NawaCaptcha bind:token action="login" types={['slider', 'pairs']} />` (never widens them).
38
+
39
+ Then verify on your backend before trusting the request โ€” see the [full guide](https://github.com/oriebalzyuot96/nawa-captcha#readme).
40
+
41
+ ๐Ÿ“– Docs: https://oriebalzyuot96.github.io/nawa-captcha/ ยท ๐Ÿ’ป Source: https://github.com/oriebalzyuot96/nawa-captcha
42
+
43
+ MIT ยฉ oriebalzyuot96
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "@nawa-captcha/svelte",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Nawa Captcha for Svelte 5: accessible, self-hosted puzzle CAPTCHA component โ€” a privacy-friendly reCAPTCHA alternative.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "svelte": "./src/index.js",
8
+ "types": "./src/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./src/index.d.ts",
12
+ "svelte": "./src/index.js",
13
+ "default": "./src/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "src",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "typecheck": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings"
22
+ },
23
+ "dependencies": {
24
+ "@nawa-captcha/widget": "0.1.1"
25
+ },
26
+ "peerDependencies": {
27
+ "svelte": "^5.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "svelte": "^5.40.0",
31
+ "svelte-check": "^4.3.0"
32
+ },
33
+ "keywords": [
34
+ "svelte",
35
+ "svelte5",
36
+ "svelte-component",
37
+ "captcha",
38
+ "recaptcha-alternative",
39
+ "hcaptcha-alternative",
40
+ "turnstile-alternative",
41
+ "self-hosted-captcha",
42
+ "accessible-captcha",
43
+ "puzzle-captcha",
44
+ "slider-captcha",
45
+ "privacy",
46
+ "gdpr",
47
+ "bot-protection",
48
+ "anti-spam",
49
+ "proof-of-work",
50
+ "nawa-captcha",
51
+ "pelagic-ui",
52
+ "arabic",
53
+ "rtl"
54
+ ],
55
+ "homepage": "https://oriebalzyuot96.github.io/nawa-captcha/",
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/oriebalzyuot96/nawa-captcha.git",
59
+ "directory": "packages/svelte"
60
+ },
61
+ "bugs": "https://github.com/oriebalzyuot96/nawa-captcha/issues",
62
+ "author": "oriebalzyuot96",
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
+ }
@@ -0,0 +1,69 @@
1
+ <!--
2
+ Svelte 5 wrapper for <nawa-captcha>.
3
+ <NawaCaptcha bind:token action="login" lang="ar" onverified={(d) => โ€ฆ} />
4
+ `token` is bindable: it holds the pass token ('' until verified). Call `reset()` (via bind:this)
5
+ after the token has been used, because pass tokens are single-use.
6
+ -->
7
+ <script lang="ts">
8
+ import '@nawa-captcha/widget';
9
+ import type { NawaCaptchaElement, NawaCaptchaErrorDetail, NawaCaptchaVerifiedDetail } from '@nawa-captcha/widget';
10
+
11
+ interface Props {
12
+ siteKey?: string;
13
+ endpoint?: string;
14
+ action?: string;
15
+ lang?: 'ar' | 'en';
16
+ name?: string;
17
+ type?: string;
18
+ /** Narrows the server's allowed puzzle types (array or comma-separated). Never widens it. */
19
+ types?: string | readonly string[];
20
+ theme?: string;
21
+ appearance?: 'auto' | 'light' | 'dark' | 'high-contrast';
22
+ sound?: boolean;
23
+ volume?: number;
24
+ muted?: boolean;
25
+ token?: string;
26
+ onverified?: (detail: NawaCaptchaVerifiedDetail) => void;
27
+ onexpired?: () => void;
28
+ onerror?: (detail: NawaCaptchaErrorDetail) => void;
29
+ }
30
+
31
+ let { siteKey, endpoint, action, lang, name, type, types, theme, appearance, sound, volume, muted, token = $bindable(''), onverified, onexpired, onerror }: Props = $props();
32
+
33
+ let el: NawaCaptchaElement | undefined = $state();
34
+ const typesAttr = $derived(types === undefined ? undefined : typeof types === 'string' ? types : types.join(','));
35
+
36
+ $effect(() => {
37
+ const node = el;
38
+ if (!node) return;
39
+ const verified = (e: Event): void => {
40
+ const detail = (e as CustomEvent<NawaCaptchaVerifiedDetail>).detail;
41
+ token = detail.token;
42
+ onverified?.(detail);
43
+ };
44
+ const expired = (): void => {
45
+ token = '';
46
+ onexpired?.();
47
+ };
48
+ const failed = (e: Event): void => {
49
+ token = '';
50
+ onerror?.((e as CustomEvent<NawaCaptchaErrorDetail>).detail);
51
+ };
52
+ node.addEventListener('nawa-captcha:verified', verified);
53
+ node.addEventListener('nawa-captcha:expired', expired);
54
+ node.addEventListener('nawa-captcha:error', failed);
55
+ return () => {
56
+ node.removeEventListener('nawa-captcha:verified', verified);
57
+ node.removeEventListener('nawa-captcha:expired', expired);
58
+ node.removeEventListener('nawa-captcha:error', failed);
59
+ };
60
+ });
61
+
62
+ /** Clears the token and loads a fresh challenge. */
63
+ export function reset(): void {
64
+ token = '';
65
+ el?.reset();
66
+ }
67
+ </script>
68
+
69
+ <nawa-captcha bind:this={el} site-key={siteKey} {endpoint} {action} {lang} {name} {type} types={typesAttr} {theme} {appearance} {sound} {volume} {muted}></nawa-captcha>
@@ -0,0 +1,22 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+
3
+ // Lets Svelte's type checker know the <nawa-captcha> custom element and its attributes.
4
+ declare module 'svelte/elements' {
5
+ interface SvelteHTMLElements {
6
+ 'nawa-captcha': HTMLAttributes<HTMLElement> & {
7
+ 'site-key'?: string | undefined;
8
+ endpoint?: string | undefined;
9
+ action?: string | undefined;
10
+ name?: string | undefined;
11
+ type?: string | undefined;
12
+ types?: string | undefined;
13
+ theme?: string | undefined;
14
+ appearance?: string | undefined;
15
+ sound?: boolean | string | undefined;
16
+ volume?: number | string | undefined;
17
+ muted?: boolean | string | undefined;
18
+ };
19
+ }
20
+ }
21
+
22
+ export {};
package/src/index.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import type { Component } from 'svelte';
2
+ import type { NawaCaptchaErrorDetail, NawaCaptchaVerifiedDetail } from '@nawa-captcha/widget';
3
+
4
+ export type { NawaCaptchaErrorDetail, NawaCaptchaVerifiedDetail };
5
+
6
+ export interface NawaCaptchaProps {
7
+ siteKey?: string;
8
+ endpoint?: string;
9
+ action?: string;
10
+ lang?: 'ar' | 'en';
11
+ name?: string;
12
+ type?: string;
13
+ /** Narrows the server's allowed puzzle types. Never widens it. */
14
+ types?: string | readonly string[];
15
+ /** Theme preset or appearance shorthand (see the widget README). */
16
+ theme?: string;
17
+ appearance?: 'auto' | 'light' | 'dark' | 'high-contrast';
18
+ sound?: boolean;
19
+ volume?: number;
20
+ muted?: boolean;
21
+ token?: string;
22
+ onverified?: (detail: NawaCaptchaVerifiedDetail) => void;
23
+ onexpired?: () => void;
24
+ onerror?: (detail: NawaCaptchaErrorDetail) => void;
25
+ }
26
+
27
+ export declare const NawaCaptcha: Component<NawaCaptchaProps, { reset(): void }, 'token'>;
28
+ /** @deprecated Renamed to {@link NawaCaptcha} (Nawa Guard is now Nawa Captcha). */
29
+ export declare const NawaGuard: typeof NawaCaptcha;
30
+ /** @deprecated Renamed to NawaCaptchaProps. */
31
+ export type NawaGuardProps = NawaCaptchaProps;
package/src/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as NawaCaptcha } from './NawaCaptcha.svelte';
2
+ /** @deprecated Renamed to NawaCaptcha (Nawa Guard is now Nawa Captcha). */
3
+ export { default as NawaGuard } from './NawaCaptcha.svelte';