fix: include WASM pkg in git for Docker build

This commit is contained in:
2026-01-29 23:35:29 +00:00
parent 1a44b1085f
commit 0ab506e8c3
7 changed files with 1294 additions and 0 deletions

104
pkg/README.md Normal file
View File

@@ -0,0 +1,104 @@
# @nkode/client-wasm
nKode client compiled to WebAssembly with TypeScript bindings.
Provides OPAQUE (aPAKE) authentication flows that run entirely in the browser — no server-side secret key handling needed.
## Installation
```bash
npm install @nkode/client-wasm
```
## Usage
```typescript
import init, { NKodeClient } from '@nkode/client-wasm';
// Initialize the WASM module
await init();
const client = new NKodeClient('https://api.nkode.example.com');
// Generate a new secret key (16 random bytes, hex-encoded)
const secretKey = NKodeClient.generateSecretKey();
// Store this securely — it's the user's authentication key!
// Register a new user
await client.registerKey('user@example.com', secretKey);
// Login
const session = await client.loginKey('user@example.com', secretKey);
console.log(session.sessionId); // UUID
console.log(session.userId); // UUID
console.log(session.createdAt); // ISO 8601
console.log(session.expiresAt); // ISO 8601
// Code-based flows (for icon passcode)
await client.registerCode('user@example.com', passcodeBytes);
const codeSession = await client.loginCode('user@example.com', passcodeBytes);
```
## API
### `NKodeClient`
#### `new NKodeClient(baseUrl: string)`
Create a client connected to the nKode server.
#### `static generateSecretKey(): string`
Generate a random 16-byte secret key as a hex string (32 chars).
#### `registerKey(email: string, secretKeyHex: string): Promise<void>`
Register a new user with OPAQUE key-based registration.
#### `loginKey(email: string, secretKeyHex: string): Promise<NKodeSession>`
Login with OPAQUE key-based authentication.
#### `registerCode(email: string, passcodeBytes: Uint8Array): Promise<void>`
Register with OPAQUE code-based flow.
#### `loginCode(email: string, passcodeBytes: Uint8Array): Promise<NKodeSession>`
Login with OPAQUE code-based flow.
### `NKodeSession`
```typescript
interface NKodeSession {
sessionId: string; // UUID
userId: string; // UUID
createdAt: string; // ISO 8601 timestamp
expiresAt: string; // ISO 8601 timestamp
}
```
## Building from Source
```bash
# Prerequisites
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
# Build
./build.sh # For bundlers (webpack/vite)
./build.sh web # For ES modules
./build.sh nodejs # For Node.js
```
## Architecture
This crate is a standalone WASM bridge that:
- Uses `opaque-ke` for client-side OPAQUE protocol
- Uses the browser's Fetch API for HTTP transport
- Shares `common` types with the Rust server
- Runs entirely in the browser — no server round-trips for crypto
The OPAQUE flows (registration + login) are reimplemented for the WASM
single-threaded environment (no `Send`/`Sync` bounds, no tokio).
## Security
- Secret keys never leave the browser
- OPAQUE ensures the server never sees the user's password
- Session keys are derived from the OPAQUE protocol
- All HTTP communication should use HTTPS

148
pkg/nkode_client_wasm.d.ts vendored Normal file
View File

@@ -0,0 +1,148 @@
/* tslint:disable */
/* eslint-disable */
export class NKodeClient {
free(): void;
[Symbol.dispose](): void;
/**
* Login with OPAQUE code-based authentication.
* Stores the session key internally for subsequent authenticated requests.
*
* @param email - User's email address
* @param passcodeBytes - Passcode as Uint8Array
* @returns Promise<NKodeSession>
*/
loginCode(email: string, passcode_bytes: Uint8Array): Promise<any>;
/**
* Get the current session's user ID, or null if not logged in.
*/
getUserId(): string | undefined;
/**
* Check if the client has an active session (from a prior login call).
*/
hasSession(): boolean;
/**
* Register a new user via OPAQUE key-based registration.
*
* @param email - User's email address
* @param secretKeyHex - 16-byte secret key as hex string (32 chars)
* @returns Promise<void> - Resolves on success, rejects with error string
*/
registerKey(email: string, secret_key_hex: string): Promise<void>;
/**
* Clear the stored session (local logout).
*/
clearSession(): void;
/**
* Fetch new icons from the server (requires active key session).
*
* @param count - Number of icons to fetch
* @returns Promise<IconsResponse> - JSON: { icons: [{ file_name, file_type, img_data }] }
*/
getNewIcons(count: number): Promise<any>;
/**
* Register via OPAQUE code-based registration.
*
* @param email - User's email address
* @param passcodeBytes - Passcode as Uint8Array
* @returns Promise<void>
*/
registerCode(email: string, passcode_bytes: Uint8Array): Promise<void>;
/**
* Get login data for a user (requires active session).
*
* @param userId - Target user ID (must match session user)
* @returns Promise<LoginDataPayload> - JSON with keypad config
*/
getLoginData(user_id: string): Promise<any>;
/**
* Create new login data on the server (requires active key session).
*
* @param loginDataJson - JSON string of LoginDataPayload
* @returns Promise<void>
*/
postLoginData(login_data_json: string): Promise<void>;
/**
* Update login data on the server (requires active key session).
*
* @param loginDataJson - JSON string of LoginDataPayload
* @returns Promise<void>
*/
updateLoginData(login_data_json: string): Promise<void>;
/**
* Decipher key selections into OPAQUE passcode bytes for code login.
* Call this after the user taps their nKode sequence on the keypad.
*
* @param userId - The user's ID
* @param secretKeyHex - The user's secret key as hex
* @param loginDataBytes - Raw JSON bytes of login data (from server)
* @param keySelections - Array of key indices the user tapped
* @returns Uint8Array - The passcode bytes to pass to loginCode()
*/
decipherSelection(secret_key_hex: string, login_data_json: string, key_selections: Uint32Array): Uint8Array;
/**
* Prepare for code login: fetch login data, reconstruct keypad, and fetch icons.
* Returns the keypad configuration with icons for UI display.
*
* Also stores the raw login data JSON internally for decipherSelection().
*
* @param userId - The user's ID
* @param secretKeyHex - The user's secret key as hex string
* @returns Promise<CodeLoginData> - { keypadIndices, propertiesPerKey, numberOfKeys, mask, icons, loginDataJson }
*/
prepareCodeLogin(user_id: string, secret_key_hex: string): Promise<any>;
/**
* Generate a new random 16-byte secret key, returned as a hex string (32 chars).
*/
static generateSecretKey(): string;
/**
* Prepare icons for code registration (requires active key session).
* Fetches icons from the server and randomizes their names via ChaCha20.
* Stores intermediate state internally for completeCodeRegistration().
*
* @returns Promise<IconsResponse> - JSON: { icons: [{ file_name, file_type, img_data }] }
*/
prepareCodeRegistration(): Promise<any>;
/**
* Complete code registration after icon selection.
* Enciphers the selection, registers OPAQUE code auth, and stores login data.
*
* @param selectedIndices - Array of icon indices the user selected (global indices, not key indices)
* @returns Promise<void>
*/
completeCodeRegistration(selected_indices: Uint32Array): Promise<void>;
/**
* Complete code registration with email (full version).
* Enciphers the selection, registers OPAQUE code auth, and stores login data on server.
*
* @param email - User's email address
* @param selectedIndices - Uint32Array of icon indices the user selected
* @returns Promise<void>
*/
completeCodeRegistrationWithEmail(email: string, selected_indices: Uint32Array): Promise<void>;
/**
* Create a new client pointed at the given nKode server base URL.
*/
constructor(base_url: string);
/**
* Login with OPAQUE key-based authentication.
* Stores the session key internally for subsequent authenticated requests.
*
* @param email - User's email address
* @param secretKeyHex - 16-byte secret key as hex string
* @returns Promise<NKodeSession> - Session info object
*/
loginKey(email: string, secret_key_hex: string): Promise<any>;
/**
* Set (store) icons on the server (requires active key session).
*
* @param iconsJson - JSON string of { icons: [{ file_name, file_type, img_data }] }
* @returns Promise<void>
*/
setIcons(icons_json: string): Promise<void>;
}
/**
* Initialize panic hook for better error messages in browser console.
*/
export function init(): void;

5
pkg/nkode_client_wasm.js Normal file
View File

@@ -0,0 +1,5 @@
import * as wasm from "./nkode_client_wasm_bg.wasm";
export * from "./nkode_client_wasm_bg.js";
import { __wbg_set_wasm } from "./nkode_client_wasm_bg.js";
__wbg_set_wasm(wasm);
wasm.__wbindgen_start();

984
pkg/nkode_client_wasm_bg.js Normal file
View File

@@ -0,0 +1,984 @@
let wasm;
export function __wbg_set_wasm(val) {
wasm = val;
}
function addToExternrefTable0(obj) {
const idx = wasm.__externref_table_alloc();
wasm.__wbindgen_externrefs.set(idx, obj);
return idx;
}
const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined')
? { register: () => {}, unregister: () => {} }
: new FinalizationRegistry(state => state.dtor(state.a, state.b));
function debugString(val) {
// primitive types
const type = typeof val;
if (type == 'number' || type == 'boolean' || val == null) {
return `${val}`;
}
if (type == 'string') {
return `"${val}"`;
}
if (type == 'symbol') {
const description = val.description;
if (description == null) {
return 'Symbol';
} else {
return `Symbol(${description})`;
}
}
if (type == 'function') {
const name = val.name;
if (typeof name == 'string' && name.length > 0) {
return `Function(${name})`;
} else {
return 'Function';
}
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = '[';
if (length > 0) {
debug += debugString(val[0]);
}
for(let i = 1; i < length; i++) {
debug += ', ' + debugString(val[i]);
}
debug += ']';
return debug;
}
// Test for built-in
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
let className;
if (builtInMatches && builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == 'Object') {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return 'Object(' + JSON.stringify(val) + ')';
} catch (_) {
return 'Object';
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
function getArrayU8FromWasm0(ptr, len) {
ptr = ptr >>> 0;
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
}
let cachedDataViewMemory0 = null;
function getDataViewMemory0() {
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
}
return cachedDataViewMemory0;
}
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return decodeText(ptr, len);
}
let cachedUint32ArrayMemory0 = null;
function getUint32ArrayMemory0() {
if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
}
return cachedUint32ArrayMemory0;
}
let cachedUint8ArrayMemory0 = null;
function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}
function handleError(f, args) {
try {
return f.apply(this, args);
} catch (e) {
const idx = addToExternrefTable0(e);
wasm.__wbindgen_exn_store(idx);
}
}
function isLikeNone(x) {
return x === undefined || x === null;
}
function makeMutClosure(arg0, arg1, dtor, f) {
const state = { a: arg0, b: arg1, cnt: 1, dtor };
const real = (...args) => {
// First up with a closure we increment the internal reference
// count. This ensures that the Rust closure environment won't
// be deallocated while we're invoking it.
state.cnt++;
const a = state.a;
state.a = 0;
try {
return f(a, state.b, ...args);
} finally {
state.a = a;
real._wbg_cb_unref();
}
};
real._wbg_cb_unref = () => {
if (--state.cnt === 0) {
state.dtor(state.a, state.b);
state.a = 0;
CLOSURE_DTORS.unregister(state);
}
};
CLOSURE_DTORS.register(real, state, state);
return real;
}
function passArray32ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 4, 4) >>> 0;
getUint32ArrayMemory0().set(arg, ptr / 4);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1, 1) >>> 0;
getUint8ArrayMemory0().set(arg, ptr / 1);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getUint8ArrayMemory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
const ret = cachedTextEncoder.encodeInto(arg, view);
offset += ret.written;
ptr = realloc(ptr, len, offset, 1) >>> 0;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function takeFromExternrefTable0(idx) {
const value = wasm.__wbindgen_externrefs.get(idx);
wasm.__externref_table_dealloc(idx);
return value;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
const MAX_SAFARI_DECODE_BYTES = 2146435072;
let numBytesDecoded = 0;
function decodeText(ptr, len) {
numBytesDecoded += len;
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
numBytesDecoded = len;
}
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}
const cachedTextEncoder = new TextEncoder();
if (!('encodeInto' in cachedTextEncoder)) {
cachedTextEncoder.encodeInto = function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
}
}
let WASM_VECTOR_LEN = 0;
function wasm_bindgen__convert__closures_____invoke__h8f97ce5df83102bb(arg0, arg1, arg2) {
wasm.wasm_bindgen__convert__closures_____invoke__h8f97ce5df83102bb(arg0, arg1, arg2);
}
function wasm_bindgen__convert__closures_____invoke__h01837f788748d23a(arg0, arg1, arg2, arg3) {
wasm.wasm_bindgen__convert__closures_____invoke__h01837f788748d23a(arg0, arg1, arg2, arg3);
}
const __wbindgen_enum_RequestMode = ["same-origin", "no-cors", "cors", "navigate"];
const NKodeClientFinalization = (typeof FinalizationRegistry === 'undefined')
? { register: () => {}, unregister: () => {} }
: new FinalizationRegistry(ptr => wasm.__wbg_nkodeclient_free(ptr >>> 0, 1));
/**
* nKode client for browser usage.
*
* Exposes OPAQUE registration and login flows via WebAssembly,
* plus authenticated endpoint access using stored session keys.
*
* ## TypeScript Usage
* ```ts
* import init, { NKodeClient } from 'nkode-client-wasm';
*
* await init();
* const client = new NKodeClient('https://api.nkode.example.com');
*
* const key = NKodeClient.generateSecretKey();
* await client.registerKey('user@example.com', key);
* const session = await client.loginKey('user@example.com', key);
*
* // Authenticated endpoints (uses stored session key from login)
* const icons = await client.getNewIcons(9);
* ```
*/
export class NKodeClient {
__destroy_into_raw() {
const ptr = this.__wbg_ptr;
this.__wbg_ptr = 0;
NKodeClientFinalization.unregister(this);
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_nkodeclient_free(ptr, 0);
}
/**
* Login with OPAQUE code-based authentication.
* Stores the session key internally for subsequent authenticated requests.
*
* @param email - User's email address
* @param passcodeBytes - Passcode as Uint8Array
* @returns Promise<NKodeSession>
* @param {string} email
* @param {Uint8Array} passcode_bytes
* @returns {Promise<any>}
*/
loginCode(email, passcode_bytes) {
const ptr0 = passStringToWasm0(email, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passArray8ToWasm0(passcode_bytes, wasm.__wbindgen_malloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_loginCode(this.__wbg_ptr, ptr0, len0, ptr1, len1);
return ret;
}
/**
* Get the current session's user ID, or null if not logged in.
* @returns {string | undefined}
*/
getUserId() {
const ret = wasm.nkodeclient_getUserId(this.__wbg_ptr);
let v1;
if (ret[0] !== 0) {
v1 = getStringFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
}
return v1;
}
/**
* Check if the client has an active session (from a prior login call).
* @returns {boolean}
*/
hasSession() {
const ret = wasm.nkodeclient_hasSession(this.__wbg_ptr);
return ret !== 0;
}
/**
* Register a new user via OPAQUE key-based registration.
*
* @param email - User's email address
* @param secretKeyHex - 16-byte secret key as hex string (32 chars)
* @returns Promise<void> - Resolves on success, rejects with error string
* @param {string} email
* @param {string} secret_key_hex
* @returns {Promise<void>}
*/
registerKey(email, secret_key_hex) {
const ptr0 = passStringToWasm0(email, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(secret_key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_registerKey(this.__wbg_ptr, ptr0, len0, ptr1, len1);
return ret;
}
/**
* Clear the stored session (local logout).
*/
clearSession() {
wasm.nkodeclient_clearSession(this.__wbg_ptr);
}
/**
* Fetch new icons from the server (requires active key session).
*
* @param count - Number of icons to fetch
* @returns Promise<IconsResponse> - JSON: { icons: [{ file_name, file_type, img_data }] }
* @param {number} count
* @returns {Promise<any>}
*/
getNewIcons(count) {
const ret = wasm.nkodeclient_getNewIcons(this.__wbg_ptr, count);
return ret;
}
/**
* Register via OPAQUE code-based registration.
*
* @param email - User's email address
* @param passcodeBytes - Passcode as Uint8Array
* @returns Promise<void>
* @param {string} email
* @param {Uint8Array} passcode_bytes
* @returns {Promise<void>}
*/
registerCode(email, passcode_bytes) {
const ptr0 = passStringToWasm0(email, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passArray8ToWasm0(passcode_bytes, wasm.__wbindgen_malloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_registerCode(this.__wbg_ptr, ptr0, len0, ptr1, len1);
return ret;
}
/**
* Get login data for a user (requires active session).
*
* @param userId - Target user ID (must match session user)
* @returns Promise<LoginDataPayload> - JSON with keypad config
* @param {string} user_id
* @returns {Promise<any>}
*/
getLoginData(user_id) {
const ptr0 = passStringToWasm0(user_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_getLoginData(this.__wbg_ptr, ptr0, len0);
return ret;
}
/**
* Create new login data on the server (requires active key session).
*
* @param loginDataJson - JSON string of LoginDataPayload
* @returns Promise<void>
* @param {string} login_data_json
* @returns {Promise<void>}
*/
postLoginData(login_data_json) {
const ptr0 = passStringToWasm0(login_data_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_postLoginData(this.__wbg_ptr, ptr0, len0);
return ret;
}
/**
* Update login data on the server (requires active key session).
*
* @param loginDataJson - JSON string of LoginDataPayload
* @returns Promise<void>
* @param {string} login_data_json
* @returns {Promise<void>}
*/
updateLoginData(login_data_json) {
const ptr0 = passStringToWasm0(login_data_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_updateLoginData(this.__wbg_ptr, ptr0, len0);
return ret;
}
/**
* Decipher key selections into OPAQUE passcode bytes for code login.
* Call this after the user taps their nKode sequence on the keypad.
*
* @param userId - The user's ID
* @param secretKeyHex - The user's secret key as hex
* @param loginDataBytes - Raw JSON bytes of login data (from server)
* @param keySelections - Array of key indices the user tapped
* @returns Uint8Array - The passcode bytes to pass to loginCode()
* @param {string} secret_key_hex
* @param {string} login_data_json
* @param {Uint32Array} key_selections
* @returns {Uint8Array}
*/
decipherSelection(secret_key_hex, login_data_json, key_selections) {
const ptr0 = passStringToWasm0(secret_key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(login_data_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passArray32ToWasm0(key_selections, wasm.__wbindgen_malloc);
const len2 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_decipherSelection(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v4 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v4;
}
/**
* Prepare for code login: fetch login data, reconstruct keypad, and fetch icons.
* Returns the keypad configuration with icons for UI display.
*
* Also stores the raw login data JSON internally for decipherSelection().
*
* @param userId - The user's ID
* @param secretKeyHex - The user's secret key as hex string
* @returns Promise<CodeLoginData> - { keypadIndices, propertiesPerKey, numberOfKeys, mask, icons, loginDataJson }
* @param {string} user_id
* @param {string} secret_key_hex
* @returns {Promise<any>}
*/
prepareCodeLogin(user_id, secret_key_hex) {
const ptr0 = passStringToWasm0(user_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(secret_key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_prepareCodeLogin(this.__wbg_ptr, ptr0, len0, ptr1, len1);
return ret;
}
/**
* Generate a new random 16-byte secret key, returned as a hex string (32 chars).
* @returns {string}
*/
static generateSecretKey() {
let deferred1_0;
let deferred1_1;
try {
const ret = wasm.nkodeclient_generateSecretKey();
deferred1_0 = ret[0];
deferred1_1 = ret[1];
return getStringFromWasm0(ret[0], ret[1]);
} finally {
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
}
}
/**
* Prepare icons for code registration (requires active key session).
* Fetches icons from the server and randomizes their names via ChaCha20.
* Stores intermediate state internally for completeCodeRegistration().
*
* @returns Promise<IconsResponse> - JSON: { icons: [{ file_name, file_type, img_data }] }
* @returns {Promise<any>}
*/
prepareCodeRegistration() {
const ret = wasm.nkodeclient_prepareCodeRegistration(this.__wbg_ptr);
return ret;
}
/**
* Complete code registration after icon selection.
* Enciphers the selection, registers OPAQUE code auth, and stores login data.
*
* @param selectedIndices - Array of icon indices the user selected (global indices, not key indices)
* @returns Promise<void>
* @param {Uint32Array} selected_indices
* @returns {Promise<void>}
*/
completeCodeRegistration(selected_indices) {
const ptr0 = passArray32ToWasm0(selected_indices, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_completeCodeRegistration(this.__wbg_ptr, ptr0, len0);
return ret;
}
/**
* Complete code registration with email (full version).
* Enciphers the selection, registers OPAQUE code auth, and stores login data on server.
*
* @param email - User's email address
* @param selectedIndices - Uint32Array of icon indices the user selected
* @returns Promise<void>
* @param {string} email
* @param {Uint32Array} selected_indices
* @returns {Promise<void>}
*/
completeCodeRegistrationWithEmail(email, selected_indices) {
const ptr0 = passStringToWasm0(email, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passArray32ToWasm0(selected_indices, wasm.__wbindgen_malloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_completeCodeRegistrationWithEmail(this.__wbg_ptr, ptr0, len0, ptr1, len1);
return ret;
}
/**
* Create a new client pointed at the given nKode server base URL.
* @param {string} base_url
*/
constructor(base_url) {
const ptr0 = passStringToWasm0(base_url, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_new(ptr0, len0);
this.__wbg_ptr = ret >>> 0;
NKodeClientFinalization.register(this, this.__wbg_ptr, this);
return this;
}
/**
* Login with OPAQUE key-based authentication.
* Stores the session key internally for subsequent authenticated requests.
*
* @param email - User's email address
* @param secretKeyHex - 16-byte secret key as hex string
* @returns Promise<NKodeSession> - Session info object
* @param {string} email
* @param {string} secret_key_hex
* @returns {Promise<any>}
*/
loginKey(email, secret_key_hex) {
const ptr0 = passStringToWasm0(email, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(secret_key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_loginKey(this.__wbg_ptr, ptr0, len0, ptr1, len1);
return ret;
}
/**
* Set (store) icons on the server (requires active key session).
*
* @param iconsJson - JSON string of { icons: [{ file_name, file_type, img_data }] }
* @returns Promise<void>
* @param {string} icons_json
* @returns {Promise<void>}
*/
setIcons(icons_json) {
const ptr0 = passStringToWasm0(icons_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.nkodeclient_setIcons(this.__wbg_ptr, ptr0, len0);
return ret;
}
}
if (Symbol.dispose) NKodeClient.prototype[Symbol.dispose] = NKodeClient.prototype.free;
/**
* Initialize panic hook for better error messages in browser console.
*/
export function init() {
wasm.init();
}
export function __wbg_Error_52673b7de5a0ca89(arg0, arg1) {
const ret = Error(getStringFromWasm0(arg0, arg1));
return ret;
};
export function __wbg_String_8f0eb39a4a4c2f66(arg0, arg1) {
const ret = String(arg1);
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
};
export function __wbg___wbindgen_debug_string_adfb662ae34724b6(arg0, arg1) {
const ret = debugString(arg1);
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
};
export function __wbg___wbindgen_is_function_8d400b8b1af978cd(arg0) {
const ret = typeof(arg0) === 'function';
return ret;
};
export function __wbg___wbindgen_is_object_ce774f3490692386(arg0) {
const val = arg0;
const ret = typeof(val) === 'object' && val !== null;
return ret;
};
export function __wbg___wbindgen_is_string_704ef9c8fc131030(arg0) {
const ret = typeof(arg0) === 'string';
return ret;
};
export function __wbg___wbindgen_is_undefined_f6b95eab589e0269(arg0) {
const ret = arg0 === undefined;
return ret;
};
export function __wbg___wbindgen_string_get_a2a31e16edf96e42(arg0, arg1) {
const obj = arg1;
const ret = typeof(obj) === 'string' ? obj : undefined;
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
};
export function __wbg___wbindgen_throw_dd24417ed36fc46e(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
export function __wbg__wbg_cb_unref_87dfb5aaa0cbcea7(arg0) {
arg0._wbg_cb_unref();
};
export function __wbg_arrayBuffer_c04af4fce566092d() { return handleError(function (arg0) {
const ret = arg0.arrayBuffer();
return ret;
}, arguments) };
export function __wbg_call_3020136f7a2d6e44() { return handleError(function (arg0, arg1, arg2) {
const ret = arg0.call(arg1, arg2);
return ret;
}, arguments) };
export function __wbg_call_abb4ff46ce38be40() { return handleError(function (arg0, arg1) {
const ret = arg0.call(arg1);
return ret;
}, arguments) };
export function __wbg_crypto_574e78ad8b13b65f(arg0) {
const ret = arg0.crypto;
return ret;
};
export function __wbg_error_7534b8e9a36f1ab4(arg0, arg1) {
let deferred0_0;
let deferred0_1;
try {
deferred0_0 = arg0;
deferred0_1 = arg1;
console.error(getStringFromWasm0(arg0, arg1));
} finally {
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
}
};
export function __wbg_fetch_8119fbf8d0e4f4d1(arg0, arg1) {
const ret = arg0.fetch(arg1);
return ret;
};
export function __wbg_getRandomValues_1c61fac11405ffdc() { return handleError(function (arg0, arg1) {
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
}, arguments) };
export function __wbg_getRandomValues_b8f5dbd5f3995a9e() { return handleError(function (arg0, arg1) {
arg0.getRandomValues(arg1);
}, arguments) };
export function __wbg_getTime_ad1e9878a735af08(arg0) {
const ret = arg0.getTime();
return ret;
};
export function __wbg_headers_850c3fb50632ae78(arg0) {
const ret = arg0.headers;
return ret;
};
export function __wbg_instanceof_Response_cd74d1c2ac92cb0b(arg0) {
let result;
try {
result = arg0 instanceof Response;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
export function __wbg_instanceof_Window_b5cf7783caa68180(arg0) {
let result;
try {
result = arg0 instanceof Window;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
export function __wbg_length_22ac23eaec9d8053(arg0) {
const ret = arg0.length;
return ret;
};
export function __wbg_msCrypto_a61aeb35a24c1329(arg0) {
const ret = arg0.msCrypto;
return ret;
};
export function __wbg_new_0_23cedd11d9b40c9d() {
const ret = new Date();
return ret;
};
export function __wbg_new_1ba21ce319a06297() {
const ret = new Object();
return ret;
};
export function __wbg_new_25f239778d6112b9() {
const ret = new Array();
return ret;
};
export function __wbg_new_6421f6084cc5bc5a(arg0) {
const ret = new Uint8Array(arg0);
return ret;
};
export function __wbg_new_8a6f238a6ece86ea() {
const ret = new Error();
return ret;
};
export function __wbg_new_b546ae120718850e() {
const ret = new Map();
return ret;
};
export function __wbg_new_ff12d2b041fb48f1(arg0, arg1) {
try {
var state0 = {a: arg0, b: arg1};
var cb0 = (arg0, arg1) => {
const a = state0.a;
state0.a = 0;
try {
return wasm_bindgen__convert__closures_____invoke__h01837f788748d23a(a, state0.b, arg0, arg1);
} finally {
state0.a = a;
}
};
const ret = new Promise(cb0);
return ret;
} finally {
state0.a = state0.b = 0;
}
};
export function __wbg_new_from_slice_f9c22b9153b26992(arg0, arg1) {
const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
return ret;
};
export function __wbg_new_no_args_cb138f77cf6151ee(arg0, arg1) {
const ret = new Function(getStringFromWasm0(arg0, arg1));
return ret;
};
export function __wbg_new_with_length_aa5eaf41d35235e5(arg0) {
const ret = new Uint8Array(arg0 >>> 0);
return ret;
};
export function __wbg_new_with_str_and_init_c5748f76f5108934() { return handleError(function (arg0, arg1, arg2) {
const ret = new Request(getStringFromWasm0(arg0, arg1), arg2);
return ret;
}, arguments) };
export function __wbg_node_905d3e251edff8a2(arg0) {
const ret = arg0.node;
return ret;
};
export function __wbg_ok_dd98ecb60d721e20(arg0) {
const ret = arg0.ok;
return ret;
};
export function __wbg_process_dc0fbacc7c1c06f7(arg0) {
const ret = arg0.process;
return ret;
};
export function __wbg_prototypesetcall_dfe9b766cdc1f1fd(arg0, arg1, arg2) {
Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
};
export function __wbg_queueMicrotask_9b549dfce8865860(arg0) {
const ret = arg0.queueMicrotask;
return ret;
};
export function __wbg_queueMicrotask_fca69f5bfad613a5(arg0) {
queueMicrotask(arg0);
};
export function __wbg_randomFillSync_ac0988aba3254290() { return handleError(function (arg0, arg1) {
arg0.randomFillSync(arg1);
}, arguments) };
export function __wbg_require_60cc747a6bc5215a() { return handleError(function () {
const ret = module.require;
return ret;
}, arguments) };
export function __wbg_resolve_fd5bfbaa4ce36e1e(arg0) {
const ret = Promise.resolve(arg0);
return ret;
};
export function __wbg_set_3f1d0b984ed272ed(arg0, arg1, arg2) {
arg0[arg1] = arg2;
};
export function __wbg_set_425eb8b710d5beee() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
arg0.set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
}, arguments) };
export function __wbg_set_781438a03c0c3c81() { return handleError(function (arg0, arg1, arg2) {
const ret = Reflect.set(arg0, arg1, arg2);
return ret;
}, arguments) };
export function __wbg_set_7df433eea03a5c14(arg0, arg1, arg2) {
arg0[arg1 >>> 0] = arg2;
};
export function __wbg_set_body_8e743242d6076a4f(arg0, arg1) {
arg0.body = arg1;
};
export function __wbg_set_efaaf145b9377369(arg0, arg1, arg2) {
const ret = arg0.set(arg1, arg2);
return ret;
};
export function __wbg_set_method_76c69e41b3570627(arg0, arg1, arg2) {
arg0.method = getStringFromWasm0(arg1, arg2);
};
export function __wbg_set_mode_611016a6818fc690(arg0, arg1) {
arg0.mode = __wbindgen_enum_RequestMode[arg1];
};
export function __wbg_stack_0ed75d68575b0f3c(arg0, arg1) {
const ret = arg1.stack;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
};
export function __wbg_static_accessor_GLOBAL_769e6b65d6557335() {
const ret = typeof global === 'undefined' ? null : global;
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
};
export function __wbg_static_accessor_GLOBAL_THIS_60cf02db4de8e1c1() {
const ret = typeof globalThis === 'undefined' ? null : globalThis;
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
};
export function __wbg_static_accessor_SELF_08f5a74c69739274() {
const ret = typeof self === 'undefined' ? null : self;
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
};
export function __wbg_static_accessor_WINDOW_a8924b26aa92d024() {
const ret = typeof window === 'undefined' ? null : window;
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
};
export function __wbg_status_9bfc680efca4bdfd(arg0) {
const ret = arg0.status;
return ret;
};
export function __wbg_subarray_845f2f5bce7d061a(arg0, arg1, arg2) {
const ret = arg0.subarray(arg1 >>> 0, arg2 >>> 0);
return ret;
};
export function __wbg_text_51046bb33d257f63() { return handleError(function (arg0) {
const ret = arg0.text();
return ret;
}, arguments) };
export function __wbg_then_429f7caf1026411d(arg0, arg1, arg2) {
const ret = arg0.then(arg1, arg2);
return ret;
};
export function __wbg_then_4f95312d68691235(arg0, arg1) {
const ret = arg0.then(arg1);
return ret;
};
export function __wbg_versions_c01dfd4722a88165(arg0) {
const ret = arg0.versions;
return ret;
};
export function __wbindgen_cast_2241b6af4c4b2941(arg0, arg1) {
// Cast intrinsic for `Ref(String) -> Externref`.
const ret = getStringFromWasm0(arg0, arg1);
return ret;
};
export function __wbindgen_cast_4625c577ab2ec9ee(arg0) {
// Cast intrinsic for `U64 -> Externref`.
const ret = BigInt.asUintN(64, arg0);
return ret;
};
export function __wbindgen_cast_9ae0607507abb057(arg0) {
// Cast intrinsic for `I64 -> Externref`.
const ret = arg0;
return ret;
};
export function __wbindgen_cast_cb9088102bce6b30(arg0, arg1) {
// Cast intrinsic for `Ref(Slice(U8)) -> NamedExternref("Uint8Array")`.
const ret = getArrayU8FromWasm0(arg0, arg1);
return ret;
};
export function __wbindgen_cast_d6cd19b81560fd6e(arg0) {
// Cast intrinsic for `F64 -> Externref`.
const ret = arg0;
return ret;
};
export function __wbindgen_cast_f2cc0f2a96e2ef5b(arg0, arg1) {
// Cast intrinsic for `Closure(Closure { dtor_idx: 115, function: Function { arguments: [Externref], shim_idx: 116, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h28b97059ae600264, wasm_bindgen__convert__closures_____invoke__h8f97ce5df83102bb);
return ret;
};
export function __wbindgen_init_externref_table() {
const table = wasm.__wbindgen_externrefs;
const offset = table.grow(4);
table.set(0, undefined);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
};

Binary file not shown.

35
pkg/nkode_client_wasm_bg.wasm.d.ts vendored Normal file
View File

@@ -0,0 +1,35 @@
/* tslint:disable */
/* eslint-disable */
export const memory: WebAssembly.Memory;
export const __wbg_nkodeclient_free: (a: number, b: number) => void;
export const init: () => void;
export const nkodeclient_clearSession: (a: number) => void;
export const nkodeclient_completeCodeRegistration: (a: number, b: number, c: number) => any;
export const nkodeclient_completeCodeRegistrationWithEmail: (a: number, b: number, c: number, d: number, e: number) => any;
export const nkodeclient_decipherSelection: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
export const nkodeclient_generateSecretKey: () => [number, number];
export const nkodeclient_getLoginData: (a: number, b: number, c: number) => any;
export const nkodeclient_getNewIcons: (a: number, b: number) => any;
export const nkodeclient_getUserId: (a: number) => [number, number];
export const nkodeclient_hasSession: (a: number) => number;
export const nkodeclient_loginCode: (a: number, b: number, c: number, d: number, e: number) => any;
export const nkodeclient_loginKey: (a: number, b: number, c: number, d: number, e: number) => any;
export const nkodeclient_new: (a: number, b: number) => number;
export const nkodeclient_postLoginData: (a: number, b: number, c: number) => any;
export const nkodeclient_prepareCodeLogin: (a: number, b: number, c: number, d: number, e: number) => any;
export const nkodeclient_prepareCodeRegistration: (a: number) => any;
export const nkodeclient_registerCode: (a: number, b: number, c: number, d: number, e: number) => any;
export const nkodeclient_registerKey: (a: number, b: number, c: number, d: number, e: number) => any;
export const nkodeclient_setIcons: (a: number, b: number, c: number) => any;
export const nkodeclient_updateLoginData: (a: number, b: number, c: number) => any;
export const wasm_bindgen__convert__closures_____invoke__h8f97ce5df83102bb: (a: number, b: number, c: any) => void;
export const wasm_bindgen__closure__destroy__h28b97059ae600264: (a: number, b: number) => void;
export const wasm_bindgen__convert__closures_____invoke__h01837f788748d23a: (a: number, b: number, c: any, d: any) => void;
export const __wbindgen_malloc: (a: number, b: number) => number;
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
export const __wbindgen_exn_store: (a: number) => void;
export const __externref_table_alloc: () => number;
export const __wbindgen_externrefs: WebAssembly.Table;
export const __wbindgen_free: (a: number, b: number, c: number) => void;
export const __externref_table_dealloc: (a: number) => void;
export const __wbindgen_start: () => void;

18
pkg/package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "nkode-client-wasm",
"type": "module",
"description": "nKode client compiled to WebAssembly with TypeScript bindings",
"version": "0.1.0",
"files": [
"nkode_client_wasm_bg.wasm",
"nkode_client_wasm.js",
"nkode_client_wasm_bg.js",
"nkode_client_wasm.d.ts"
],
"main": "nkode_client_wasm.js",
"types": "nkode_client_wasm.d.ts",
"sideEffects": [
"./nkode_client_wasm.js",
"./snippets/*"
]
}