@gnufoo/envlp 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.
Binary file
@@ -0,0 +1,24 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export const KEY_SIZE: () => number;
5
+ export const NONCE_SIZE: () => number;
6
+ export const SPEC_VERSION: () => number;
7
+ export const TAG_SIZE: () => number;
8
+ export const hasMagicPrefix: (a: number, b: number) => number;
9
+ export const inspect: (a: number, b: number) => [number, number, number];
10
+ export const keygen: () => [number, number];
11
+ export const magicBytes: () => [number, number];
12
+ export const openReconstructed: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
13
+ export const openTransmitted: (a: number, b: number, c: number, d: number) => [number, number, number, number];
14
+ export const seal: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => [number, number, number, number];
15
+ export const validate: (a: number, b: number) => [number, number, number];
16
+ export const version: () => [number, number];
17
+ export const __wbindgen_exn_store: (a: number) => void;
18
+ export const __externref_table_alloc: () => number;
19
+ export const __wbindgen_externrefs: WebAssembly.Table;
20
+ export const __wbindgen_malloc: (a: number, b: number) => number;
21
+ export const __externref_table_dealloc: (a: number) => void;
22
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
23
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
24
+ export const __wbindgen_start: () => void;
package/init.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Initialize WASM. Call once before using any WASM functions.
3
+ *
4
+ * @param wasmModule - Pass the WebAssembly.Module in Workers, omit in browser
5
+ */
6
+ export function initWasm(wasmModule?: WebAssembly.Module): Promise<void>;
7
+
8
+ /**
9
+ * Check if WASM has been initialized.
10
+ */
11
+ export function isInitialized(): boolean;
package/init.js ADDED
@@ -0,0 +1,24 @@
1
+ import init from './envlp_wasm.js';
2
+
3
+ let initialized = false;
4
+ let initPromise = null;
5
+
6
+ /**
7
+ * Initialize WASM. Call once before using any WASM functions.
8
+ *
9
+ * @param {WebAssembly.Module | undefined} wasmModule - Pass the Module in Workers, omit in browser
10
+ */
11
+ export async function initWasm(wasmModule) {
12
+ if (initialized) return;
13
+ if (initPromise) return initPromise;
14
+
15
+ initPromise = init(wasmModule).then(() => {
16
+ initialized = true;
17
+ });
18
+
19
+ return initPromise;
20
+ }
21
+
22
+ export function isInitialized() {
23
+ return initialized;
24
+ }
package/meta.d.ts ADDED
@@ -0,0 +1,85 @@
1
+ import { z } from 'zod';
2
+
3
+ export declare const inputSchema: z.ZodDiscriminatedUnion<'action', [
4
+ z.ZodObject<{
5
+ action: z.ZodLiteral<'seal'>;
6
+ key: z.ZodString;
7
+ plaintext: z.ZodString;
8
+ aad: z.ZodString;
9
+ keyId: z.ZodString;
10
+ options: z.ZodOptional<z.ZodObject<{
11
+ includeMagic: z.ZodDefault<z.ZodBoolean>;
12
+ includeAad: z.ZodDefault<z.ZodBoolean>;
13
+ }>>;
14
+ }>,
15
+ z.ZodObject<{
16
+ action: z.ZodLiteral<'openTransmitted'>;
17
+ key: z.ZodString;
18
+ envelope: z.ZodString;
19
+ }>,
20
+ z.ZodObject<{
21
+ action: z.ZodLiteral<'openReconstructed'>;
22
+ key: z.ZodString;
23
+ envelope: z.ZodString;
24
+ aad: z.ZodString;
25
+ }>,
26
+ z.ZodObject<{
27
+ action: z.ZodLiteral<'inspect'>;
28
+ envelope: z.ZodString;
29
+ }>,
30
+ z.ZodObject<{
31
+ action: z.ZodLiteral<'validate'>;
32
+ envelope: z.ZodString;
33
+ }>,
34
+ z.ZodObject<{
35
+ action: z.ZodLiteral<'keygen'>;
36
+ }>
37
+ ]>;
38
+
39
+ export declare const outputSchema: z.ZodType;
40
+
41
+ export type EnvlpInput = z.infer<typeof inputSchema>;
42
+ export type EnvlpOutput = z.infer<typeof outputSchema>;
43
+
44
+ export interface SealOptions {
45
+ includeMagic?: boolean;
46
+ includeAad?: boolean;
47
+ }
48
+
49
+ export interface InspectResult {
50
+ action: 'inspect';
51
+ version: number;
52
+ algorithm: string;
53
+ algorithmId: number;
54
+ keyId: string;
55
+ nonceHex: string;
56
+ ciphertextLen: number;
57
+ hasAad: boolean;
58
+ aadLen: number | null;
59
+ isWrappedMode: boolean;
60
+ }
61
+
62
+ export interface ValidateResult {
63
+ action: 'validate';
64
+ valid: boolean;
65
+ errors: string[];
66
+ }
67
+
68
+ export declare const meta: {
69
+ id: string;
70
+ name: string;
71
+ slug: string;
72
+ description: string;
73
+ category: 'crypto';
74
+ executionType: 'client';
75
+ inputSchema: typeof inputSchema;
76
+ outputSchema: typeof outputSchema;
77
+ positionalArgs: {
78
+ order: string[];
79
+ required: number;
80
+ };
81
+ packages: {
82
+ npm: string;
83
+ crates: string;
84
+ };
85
+ };
package/meta.js ADDED
@@ -0,0 +1,129 @@
1
+ import { z } from 'zod';
2
+
3
+ // ============================================================================
4
+ // Input Schemas (discriminated union by action)
5
+ // ============================================================================
6
+
7
+ const sealOptionsSchema = z.object({
8
+ includeMagic: z.boolean().default(true),
9
+ includeAad: z.boolean().default(true),
10
+ }).optional();
11
+
12
+ const sealAction = z.object({
13
+ action: z.literal('seal'),
14
+ key: z.string().min(1).describe('256-bit key as hex or base64'),
15
+ plaintext: z.string().min(1).describe('Plaintext as base64'),
16
+ aad: z.string().min(1).describe('AAD as JSON string'),
17
+ keyId: z.string().min(1).max(256).describe('Key identifier for envelope header'),
18
+ options: sealOptionsSchema,
19
+ });
20
+
21
+ const openTransmittedAction = z.object({
22
+ action: z.literal('openTransmitted'),
23
+ key: z.string().min(1).describe('256-bit key as hex or base64'),
24
+ envelope: z.string().min(1).describe('Envelope as base64'),
25
+ });
26
+
27
+ const openReconstructedAction = z.object({
28
+ action: z.literal('openReconstructed'),
29
+ key: z.string().min(1).describe('256-bit key as hex or base64'),
30
+ envelope: z.string().min(1).describe('Envelope as base64'),
31
+ aad: z.string().min(1).describe('AAD as JSON string'),
32
+ });
33
+
34
+ const inspectAction = z.object({
35
+ action: z.literal('inspect'),
36
+ envelope: z.string().min(1).describe('Envelope as base64'),
37
+ });
38
+
39
+ const validateAction = z.object({
40
+ action: z.literal('validate'),
41
+ envelope: z.string().min(1).describe('Envelope as base64'),
42
+ });
43
+
44
+ const keygenAction = z.object({
45
+ action: z.literal('keygen'),
46
+ });
47
+
48
+ export const inputSchema = z.discriminatedUnion('action', [
49
+ sealAction,
50
+ openTransmittedAction,
51
+ openReconstructedAction,
52
+ inspectAction,
53
+ validateAction,
54
+ keygenAction,
55
+ ]);
56
+
57
+ // ============================================================================
58
+ // Output Schemas (discriminated union by action)
59
+ // ============================================================================
60
+
61
+ const sealOutput = z.object({
62
+ action: z.literal('seal'),
63
+ envelope: z.string().describe('Envelope as base64'),
64
+ });
65
+
66
+ const openOutput = z.object({
67
+ action: z.enum(['openTransmitted', 'openReconstructed']),
68
+ plaintext: z.string().describe('Decrypted plaintext as base64'),
69
+ });
70
+
71
+ const inspectOutput = z.object({
72
+ action: z.literal('inspect'),
73
+ version: z.number().int(),
74
+ algorithm: z.string(),
75
+ algorithmId: z.number().int(),
76
+ keyId: z.string(),
77
+ nonceHex: z.string(),
78
+ ciphertextLen: z.number().int(),
79
+ hasAad: z.boolean(),
80
+ aadLen: z.number().int().nullable(),
81
+ isWrappedMode: z.boolean(),
82
+ });
83
+
84
+ const validateOutput = z.object({
85
+ action: z.literal('validate'),
86
+ valid: z.boolean(),
87
+ errors: z.array(z.string()),
88
+ });
89
+
90
+ const keygenOutput = z.object({
91
+ action: z.literal('keygen'),
92
+ key: z.string().describe('256-bit key as hex'),
93
+ });
94
+
95
+ export const outputSchema = z.discriminatedUnion('action', [
96
+ sealOutput,
97
+ openOutput.extend({ action: z.literal('openTransmitted') }),
98
+ openOutput.extend({ action: z.literal('openReconstructed') }),
99
+ inspectOutput,
100
+ validateOutput,
101
+ keygenOutput,
102
+ ]);
103
+
104
+ // ============================================================================
105
+ // Tool Metadata
106
+ // ============================================================================
107
+
108
+ export const meta = {
109
+ id: 'envlp',
110
+ name: 'envlp',
111
+ slug: 'envlp',
112
+ description: 'AEAD envelope encryption with XChaCha20-Poly1305 per AAED wire format spec',
113
+
114
+ category: 'crypto',
115
+ executionType: 'client',
116
+
117
+ inputSchema,
118
+ outputSchema,
119
+
120
+ positionalArgs: {
121
+ order: ['action', 'envelope'],
122
+ required: 1,
123
+ },
124
+
125
+ packages: {
126
+ npm: '@gnufoo/envlp',
127
+ crates: 'envlp-cli',
128
+ },
129
+ };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@gnufoo/envlp",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "main": "envlp_wasm.js",
6
+ "types": "envlp_wasm.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./envlp_wasm.d.ts",
10
+ "import": "./envlp_wasm.js"
11
+ },
12
+ "./meta": {
13
+ "types": "./meta.d.ts",
14
+ "import": "./meta.js"
15
+ },
16
+ "./tool": {
17
+ "types": "./tool.d.ts",
18
+ "import": "./tool.js"
19
+ },
20
+ "./init": {
21
+ "types": "./init.d.ts",
22
+ "import": "./init.js"
23
+ }
24
+ },
25
+ "dependencies": {
26
+ "zod": "^3.24.0"
27
+ },
28
+ "files": [
29
+ "*.js",
30
+ "*.d.ts",
31
+ "*.wasm"
32
+ ],
33
+ "sideEffects": false,
34
+ "keywords": [
35
+ "aead",
36
+ "envelope",
37
+ "encryption",
38
+ "xchacha20",
39
+ "poly1305",
40
+ "cbor",
41
+ "wasm"
42
+ ],
43
+ "license": "MIT OR Apache-2.0",
44
+ "description": "AEAD envelope encryption library (AAED wire format spec)"
45
+ }
package/tool.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { meta, EnvlpInput, EnvlpOutput } from './meta.js';
2
+ import type { initWasm, isInitialized } from './init.js';
3
+
4
+ export declare const toolDefinition: typeof meta & {
5
+ initWasm: typeof initWasm;
6
+ isInitialized: typeof isInitialized;
7
+ execute(input: EnvlpInput): Promise<EnvlpOutput>;
8
+ };
package/tool.js ADDED
@@ -0,0 +1,169 @@
1
+ import { meta, inputSchema } from './meta.js';
2
+ import { initWasm, isInitialized } from './init.js';
3
+ import {
4
+ keygen,
5
+ seal,
6
+ openTransmitted,
7
+ openReconstructed,
8
+ inspect,
9
+ validate,
10
+ } from './envlp_wasm.js';
11
+
12
+ // ============================================================================
13
+ // Encoding utilities
14
+ // ============================================================================
15
+
16
+ const hexToBytes = (hex) => {
17
+ const bytes = new Uint8Array(hex.length / 2);
18
+ for (let i = 0; i < bytes.length; i++) {
19
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
20
+ }
21
+ return bytes;
22
+ };
23
+
24
+ const bytesToHex = (bytes) =>
25
+ Array.from(bytes)
26
+ .map((b) => b.toString(16).padStart(2, '0'))
27
+ .join('');
28
+
29
+ const base64ToBytes = (base64) => {
30
+ const binary = globalThis.atob(base64);
31
+ const bytes = new Uint8Array(binary.length);
32
+ for (let i = 0; i < binary.length; i++) {
33
+ bytes[i] = binary.charCodeAt(i);
34
+ }
35
+ return bytes;
36
+ };
37
+
38
+ const bytesToBase64 = (bytes) =>
39
+ globalThis.btoa(String.fromCharCode(...bytes));
40
+
41
+ /**
42
+ * Parse a key from hex or base64 format.
43
+ * Hex keys are 64 chars, base64 keys are 44 chars (with padding).
44
+ */
45
+ const parseKey = (keyStr) => {
46
+ // Check for hex (64 chars for 32 bytes)
47
+ if (/^[0-9a-fA-F]{64}$/.test(keyStr)) {
48
+ return hexToBytes(keyStr);
49
+ }
50
+ // Assume base64
51
+ return base64ToBytes(keyStr);
52
+ };
53
+
54
+ // ============================================================================
55
+ // Tool Definition
56
+ // ============================================================================
57
+
58
+ export const toolDefinition = {
59
+ ...meta,
60
+
61
+ /**
62
+ * Initialize WASM. Must be called before execute() in Workers.
63
+ * In browsers with vite-plugin-wasm, this is optional.
64
+ */
65
+ initWasm,
66
+ isInitialized,
67
+
68
+ /**
69
+ * Execute an envlp action.
70
+ *
71
+ * @param {import('./meta.js').EnvlpInput} rawInput
72
+ * @returns {Promise<import('./meta.js').EnvlpOutput>}
73
+ */
74
+ async execute(rawInput) {
75
+ if (!isInitialized()) {
76
+ throw new Error('WASM not initialized. Call initWasm() first.');
77
+ }
78
+
79
+ const input = inputSchema.parse(rawInput);
80
+
81
+ switch (input.action) {
82
+ case 'keygen': {
83
+ const keyBytes = keygen();
84
+ return {
85
+ action: 'keygen',
86
+ key: bytesToHex(keyBytes),
87
+ };
88
+ }
89
+
90
+ case 'seal': {
91
+ const keyBytes = parseKey(input.key);
92
+ const plaintextBytes = base64ToBytes(input.plaintext);
93
+ const includeAad = input.options?.includeAad ?? true;
94
+ const includeMagic = input.options?.includeMagic ?? true;
95
+
96
+ const envelopeBytes = seal(
97
+ keyBytes,
98
+ plaintextBytes,
99
+ input.aad,
100
+ input.keyId,
101
+ includeAad,
102
+ includeMagic
103
+ );
104
+
105
+ return {
106
+ action: 'seal',
107
+ envelope: bytesToBase64(envelopeBytes),
108
+ };
109
+ }
110
+
111
+ case 'openTransmitted': {
112
+ const keyBytes = parseKey(input.key);
113
+ const envelopeBytes = base64ToBytes(input.envelope);
114
+
115
+ const plaintextBytes = openTransmitted(keyBytes, envelopeBytes);
116
+
117
+ return {
118
+ action: 'openTransmitted',
119
+ plaintext: bytesToBase64(plaintextBytes),
120
+ };
121
+ }
122
+
123
+ case 'openReconstructed': {
124
+ const keyBytes = parseKey(input.key);
125
+ const envelopeBytes = base64ToBytes(input.envelope);
126
+
127
+ const plaintextBytes = openReconstructed(
128
+ keyBytes,
129
+ envelopeBytes,
130
+ input.aad
131
+ );
132
+
133
+ return {
134
+ action: 'openReconstructed',
135
+ plaintext: bytesToBase64(plaintextBytes),
136
+ };
137
+ }
138
+
139
+ case 'inspect': {
140
+ const envelopeBytes = base64ToBytes(input.envelope);
141
+ const metadata = inspect(envelopeBytes);
142
+
143
+ return {
144
+ action: 'inspect',
145
+ version: metadata.version,
146
+ algorithm: metadata.algorithm,
147
+ algorithmId: metadata.algorithmId,
148
+ keyId: metadata.keyId,
149
+ nonceHex: metadata.nonceHex,
150
+ ciphertextLen: metadata.ciphertextLen,
151
+ hasAad: metadata.hasAad,
152
+ aadLen: metadata.aadLen,
153
+ isWrappedMode: metadata.isWrappedMode,
154
+ };
155
+ }
156
+
157
+ case 'validate': {
158
+ const envelopeBytes = base64ToBytes(input.envelope);
159
+ const result = validate(envelopeBytes);
160
+
161
+ return {
162
+ action: 'validate',
163
+ valid: result.valid,
164
+ errors: Array.from(result.errors || []),
165
+ };
166
+ }
167
+ }
168
+ },
169
+ };