@openlv/core 0.1.2 → 0.2.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.
@@ -66,7 +66,7 @@ export const generateKeyPair = async () => {
66
66
  };
67
67
  export const initEncryptionKeys = async (initParameters) => {
68
68
  const { encryptionKey, decryptionKey } = await generateKeyPair();
69
- // Note: the peer key is deliberately left undefined until discovered —
69
+ // Note: the peer key is deliberately left undefined until discovered --
70
70
  // falling back to our own key would silently encrypt to ourselves.
71
71
  const publicKey = initParameters && "publicKey" in initParameters
72
72
  ? initParameters.publicKey
@@ -1 +1 @@
1
- {"version":3,"file":"asymmetric.js","sourceRoot":"","sources":["../../src/encryption/asymmetric.ts"],"names":[],"mappings":"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","sourcesContent":["import { secretbox } from \"@noble/ciphers/salsa.js\";\nimport { x25519 } from \"@noble/curves/ed25519.js\";\n\nimport type { SessionLinkParameters } from \"../session.js\";\nimport { fromBase64, toBase64 } from \"./base64.js\";\n\nconst PUBLIC_KEY_BYTES = 32;\nconst NONCE_BYTES = 24;\n\nconst composePayload = (\n ephemeralPublicKey: Uint8Array,\n nonce: Uint8Array,\n ciphertext: Uint8Array,\n): string => {\n const payload = new Uint8Array(\n ephemeralPublicKey.length + nonce.length + ciphertext.length,\n );\n\n payload.set(ephemeralPublicKey, 0);\n payload.set(nonce, ephemeralPublicKey.length);\n payload.set(ciphertext, ephemeralPublicKey.length + nonce.length);\n\n return toBase64(payload);\n};\n\nconst decomposePayload = (\n payload: string,\n): {\n ephemeralPublicKey: Uint8Array;\n nonce: Uint8Array;\n ciphertext: Uint8Array;\n} => {\n const bytes = fromBase64(payload);\n\n if (bytes.length <= PUBLIC_KEY_BYTES + NONCE_BYTES) {\n throw new Error(\"Encrypted payload is malformed.\");\n }\n\n const ephemeralPublicKey = bytes.slice(0, PUBLIC_KEY_BYTES);\n const nonce = bytes.slice(PUBLIC_KEY_BYTES, PUBLIC_KEY_BYTES + NONCE_BYTES);\n const ciphertext = bytes.slice(PUBLIC_KEY_BYTES + NONCE_BYTES);\n\n return {\n ephemeralPublicKey,\n nonce,\n ciphertext,\n };\n};\n\nexport type EncryptionKey = {\n toString: () => string;\n encrypt: (message: string) => Promise<string>;\n};\n\nexport type DecryptionKey = {\n toString: () => string;\n decrypt: (message: string) => Promise<string>;\n};\n\nexport const createEncryptionKey = async (\n publicKey: Uint8Array,\n): Promise<EncryptionKey> => {\n if (publicKey.length !== PUBLIC_KEY_BYTES) {\n throw new Error(\n `Public key must be ${PUBLIC_KEY_BYTES} bytes, got ${publicKey.length}`,\n );\n }\n\n const serializedPublicKey = toBase64(publicKey);\n\n return {\n toString: () => serializedPublicKey,\n encrypt: async (message: string) => {\n const ephemeralSecret = x25519.utils.randomSecretKey();\n const ephemeralPublic = x25519.getPublicKey(ephemeralSecret);\n const nonce = crypto.getRandomValues(new Uint8Array(NONCE_BYTES));\n const { seal } = secretbox(\n x25519.getSharedSecret(ephemeralSecret, publicKey),\n nonce,\n );\n const ciphertext = seal(new TextEncoder().encode(message));\n\n return composePayload(ephemeralPublic, nonce, ciphertext);\n },\n };\n};\n\nexport const parseEncryptionKey = async (\n serializedKey: string,\n): Promise<EncryptionKey> => createEncryptionKey(fromBase64(serializedKey));\n\nexport const createDecryptionKey = async (\n secretKey: Uint8Array,\n): Promise<DecryptionKey> => {\n const serializedSecretKey = toBase64(secretKey);\n\n return {\n toString: () => serializedSecretKey,\n decrypt: async (message: string) => {\n if (!message) {\n throw new Error(\"Cannot decrypt an empty payload\");\n }\n\n const { ephemeralPublicKey, nonce, ciphertext }\n = decomposePayload(message);\n const { open } = secretbox(\n x25519.getSharedSecret(secretKey, ephemeralPublicKey),\n nonce,\n );\n\n return new TextDecoder().decode(open(ciphertext));\n },\n };\n};\n\nexport type EncKeypair = {\n encryptionKey: EncryptionKey;\n decryptionKey: DecryptionKey;\n};\n\nexport const generateKeyPair = async (): Promise<EncKeypair> => {\n const secretKey = x25519.utils.randomSecretKey();\n const publicKey = x25519.getPublicKey(secretKey);\n\n return {\n encryptionKey: await createEncryptionKey(publicKey),\n decryptionKey: await createDecryptionKey(secretKey),\n };\n};\n\nexport const initEncryptionKeys = async (\n initParameters?: SessionLinkParameters,\n): Promise<EncKeypair & { relyingEncryptionKey?: EncryptionKey; }> => {\n const { encryptionKey, decryptionKey } = await generateKeyPair();\n\n // Note: the peer key is deliberately left undefined until discovered —\n // falling back to our own key would silently encrypt to ourselves.\n const publicKey\n = initParameters && \"publicKey\" in initParameters\n ? (initParameters.publicKey as string)\n : undefined;\n\n return {\n encryptionKey,\n decryptionKey,\n relyingEncryptionKey: publicKey\n ? await parseEncryptionKey(publicKey)\n : undefined,\n };\n};\n"]}
1
+ {"version":3,"file":"asymmetric.js","sourceRoot":"","sources":["../../src/encryption/asymmetric.ts"],"names":[],"mappings":"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","sourcesContent":["import { secretbox } from \"@noble/ciphers/salsa.js\";\nimport { x25519 } from \"@noble/curves/ed25519.js\";\n\nimport type { SessionLinkParameters } from \"../session.js\";\nimport { fromBase64, toBase64 } from \"./base64.js\";\n\nconst PUBLIC_KEY_BYTES = 32;\nconst NONCE_BYTES = 24;\n\nconst composePayload = (\n ephemeralPublicKey: Uint8Array,\n nonce: Uint8Array,\n ciphertext: Uint8Array,\n): string => {\n const payload = new Uint8Array(\n ephemeralPublicKey.length + nonce.length + ciphertext.length,\n );\n\n payload.set(ephemeralPublicKey, 0);\n payload.set(nonce, ephemeralPublicKey.length);\n payload.set(ciphertext, ephemeralPublicKey.length + nonce.length);\n\n return toBase64(payload);\n};\n\nconst decomposePayload = (\n payload: string,\n): {\n ephemeralPublicKey: Uint8Array;\n nonce: Uint8Array;\n ciphertext: Uint8Array;\n} => {\n const bytes = fromBase64(payload);\n\n if (bytes.length <= PUBLIC_KEY_BYTES + NONCE_BYTES) {\n throw new Error(\"Encrypted payload is malformed.\");\n }\n\n const ephemeralPublicKey = bytes.slice(0, PUBLIC_KEY_BYTES);\n const nonce = bytes.slice(PUBLIC_KEY_BYTES, PUBLIC_KEY_BYTES + NONCE_BYTES);\n const ciphertext = bytes.slice(PUBLIC_KEY_BYTES + NONCE_BYTES);\n\n return {\n ephemeralPublicKey,\n nonce,\n ciphertext,\n };\n};\n\nexport type EncryptionKey = {\n toString: () => string;\n encrypt: (message: string) => Promise<string>;\n};\n\nexport type DecryptionKey = {\n toString: () => string;\n decrypt: (message: string) => Promise<string>;\n};\n\nexport const createEncryptionKey = async (\n publicKey: Uint8Array,\n): Promise<EncryptionKey> => {\n if (publicKey.length !== PUBLIC_KEY_BYTES) {\n throw new Error(\n `Public key must be ${PUBLIC_KEY_BYTES} bytes, got ${publicKey.length}`,\n );\n }\n\n const serializedPublicKey = toBase64(publicKey);\n\n return {\n toString: () => serializedPublicKey,\n encrypt: async (message: string) => {\n const ephemeralSecret = x25519.utils.randomSecretKey();\n const ephemeralPublic = x25519.getPublicKey(ephemeralSecret);\n const nonce = crypto.getRandomValues(new Uint8Array(NONCE_BYTES));\n const { seal } = secretbox(\n x25519.getSharedSecret(ephemeralSecret, publicKey),\n nonce,\n );\n const ciphertext = seal(new TextEncoder().encode(message));\n\n return composePayload(ephemeralPublic, nonce, ciphertext);\n },\n };\n};\n\nexport const parseEncryptionKey = async (\n serializedKey: string,\n): Promise<EncryptionKey> => createEncryptionKey(fromBase64(serializedKey));\n\nexport const createDecryptionKey = async (\n secretKey: Uint8Array,\n): Promise<DecryptionKey> => {\n const serializedSecretKey = toBase64(secretKey);\n\n return {\n toString: () => serializedSecretKey,\n decrypt: async (message: string) => {\n if (!message) {\n throw new Error(\"Cannot decrypt an empty payload\");\n }\n\n const { ephemeralPublicKey, nonce, ciphertext }\n = decomposePayload(message);\n const { open } = secretbox(\n x25519.getSharedSecret(secretKey, ephemeralPublicKey),\n nonce,\n );\n\n return new TextDecoder().decode(open(ciphertext));\n },\n };\n};\n\nexport type EncKeypair = {\n encryptionKey: EncryptionKey;\n decryptionKey: DecryptionKey;\n};\n\nexport const generateKeyPair = async (): Promise<EncKeypair> => {\n const secretKey = x25519.utils.randomSecretKey();\n const publicKey = x25519.getPublicKey(secretKey);\n\n return {\n encryptionKey: await createEncryptionKey(publicKey),\n decryptionKey: await createDecryptionKey(secretKey),\n };\n};\n\nexport const initEncryptionKeys = async (\n initParameters?: SessionLinkParameters,\n): Promise<EncKeypair & { relyingEncryptionKey?: EncryptionKey; }> => {\n const { encryptionKey, decryptionKey } = await generateKeyPair();\n\n // Note: the peer key is deliberately left undefined until discovered --\n // falling back to our own key would silently encrypt to ourselves.\n const publicKey\n = initParameters && \"publicKey\" in initParameters\n ? (initParameters.publicKey as string)\n : undefined;\n\n return {\n encryptionKey,\n decryptionKey,\n relyingEncryptionKey: publicKey\n ? await parseEncryptionKey(publicKey)\n : undefined,\n };\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -2,5 +2,6 @@
2
2
  /** biome-ignore-all lint/performance/noBarrelFile: package entrypoint */
3
3
  export * from "./log.js";
4
4
  export * from "./make.js";
5
+ export * from "./observable.js";
5
6
  export * from "./session.js";
6
7
  export * from "./url/index.js";
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  /** biome-ignore-all lint/performance/noBarrelFile: package entrypoint */
3
3
  export * from "./log.js";
4
4
  export * from "./make.js";
5
+ export * from "./observable.js";
5
6
  export * from "./session.js";
6
7
  export * from "./url/index.js";
7
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AAEzE,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC","sourcesContent":["/** biome-ignore-all lint/performance/noReExportAll: package entrypoint */\n/** biome-ignore-all lint/performance/noBarrelFile: package entrypoint */\n\nexport * from \"./log.js\";\nexport * from \"./make.js\";\nexport * from \"./session.js\";\nexport * from \"./url/index.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AAEzE,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC","sourcesContent":["/** biome-ignore-all lint/performance/noReExportAll: package entrypoint */\n/** biome-ignore-all lint/performance/noBarrelFile: package entrypoint */\n\nexport * from \"./log.js\";\nexport * from \"./make.js\";\nexport * from \"./observable.js\";\nexport * from \"./session.js\";\nexport * from \"./url/index.js\";\n"]}
@@ -0,0 +1,15 @@
1
+ export type Unsubscribe = () => void;
2
+ export type Observable<T> = {
3
+ get(): T;
4
+ /**
5
+ * Calls the listener synchronously with the current value, then on every
6
+ * change. The replay makes subscribe-then-check patterns race-free and
7
+ * matches what reactive consumers (e.g. Solid's `from`) expect.
8
+ */
9
+ subscribe(listener: (value: T) => void): Unsubscribe;
10
+ /** Resolves with the first value (including the current one) that matches. */
11
+ until(isMatch: (value: T) => boolean): Promise<T>;
12
+ };
13
+ /** Returns false when the value was already equal and no listener ran. */
14
+ export type Setter<T> = (value: T) => boolean;
15
+ export declare const observable: <T>(initial: T) => [Observable<T>, Setter<T>];
@@ -0,0 +1,36 @@
1
+ export const observable = (initial) => {
2
+ let value = initial;
3
+ const listeners = new Set();
4
+ const get = () => value;
5
+ const subscribe = (listener) => {
6
+ listeners.add(listener);
7
+ listener(value);
8
+ return () => listeners.delete(listener);
9
+ };
10
+ const until = (isMatch) => {
11
+ if (isMatch(value))
12
+ return Promise.resolve(value);
13
+ return new Promise((resolve) => {
14
+ const unsubscribe = subscribe((next) => {
15
+ // The replay on subscribe re-delivers the current value; it cannot
16
+ // match, because the fast path above already checked it.
17
+ if (!isMatch(next))
18
+ return;
19
+ resolve(next);
20
+ unsubscribe();
21
+ });
22
+ });
23
+ };
24
+ return [
25
+ { get, subscribe, until },
26
+ (next) => {
27
+ if (value === next)
28
+ return false;
29
+ value = next;
30
+ for (const listener of listeners)
31
+ listener(value);
32
+ return true;
33
+ }
34
+ ];
35
+ };
36
+ //# sourceMappingURL=observable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observable.js","sourceRoot":"","sources":["../src/observable.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAI,OAAU,EAA8B,EAAE;IACtE,IAAI,KAAK,GAAG,OAAO,CAAC;IACpB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEhD,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC;IAExB,MAAM,SAAS,GAAG,CAAC,QAA4B,EAAe,EAAE;QAC9D,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEhB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,OAA8B,EAAc,EAAE;QAC3D,IAAI,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAElD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;gBACrC,mEAAmE;gBACnE,yDAAyD;gBACzD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAE3B,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACL,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE;QACzB,CAAC,IAAI,EAAE,EAAE;YACP,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YAEjC,KAAK,GAAG,IAAI,CAAC;YAEb,KAAK,MAAM,QAAQ,IAAI,SAAS;gBAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;YAElD,OAAO,IAAI,CAAC;QACd,CAAC;KAAC,CAAC;AACP,CAAC,CAAC","sourcesContent":["export type Unsubscribe = () => void;\nexport type Observable<T> = {\n get(): T;\n /**\n * Calls the listener synchronously with the current value, then on every\n * change. The replay makes subscribe-then-check patterns race-free and\n * matches what reactive consumers (e.g. Solid's `from`) expect.\n */\n subscribe(listener: (value: T) => void): Unsubscribe;\n /** Resolves with the first value (including the current one) that matches. */\n until(isMatch: (value: T) => boolean): Promise<T>;\n};\n/** Returns false when the value was already equal and no listener ran. */\nexport type Setter<T> = (value: T) => boolean;\n\nexport const observable = <T>(initial: T): [Observable<T>, Setter<T>] => {\n let value = initial;\n const listeners = new Set<(value: T) => void>();\n\n const get = () => value;\n\n const subscribe = (listener: (value: T) => void): Unsubscribe => {\n listeners.add(listener);\n listener(value);\n\n return () => listeners.delete(listener);\n };\n\n const until = (isMatch: (value: T) => boolean): Promise<T> => {\n if (isMatch(value)) return Promise.resolve(value);\n\n return new Promise((resolve) => {\n const unsubscribe = subscribe((next) => {\n // The replay on subscribe re-delivers the current value; it cannot\n // match, because the fast path above already checked it.\n if (!isMatch(next)) return;\n\n resolve(next);\n unsubscribe();\n });\n });\n };\n\n return [\n { get, subscribe, until },\n (next) => {\n if (value === next) return false;\n\n value = next;\n\n for (const listener of listeners) listener(value);\n\n return true;\n }];\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlv/core",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "keywords": [
5
5
  "open-lavatory"
6
6
  ],