@kokuin/expo 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/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @kokuin/expo
2
+
3
+ ## Installation
4
+
5
+ ```sh
6
+ npm install @kokuin/expo
7
+ ```
package/lib/entry.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { KeyEntry } from '@kokuin/token';
2
+ import * as SecureStore from 'expo-secure-store';
3
+ export type StoreEntryOptions = SecureStore.SecureStoreOptions;
4
+ export declare class ExpoKeyEntry implements KeyEntry<Uint8Array> {
5
+ #private;
6
+ constructor(keyID: string, options?: StoreEntryOptions);
7
+ get keyID(): string;
8
+ get(): Uint8Array | null;
9
+ getAsync(): Promise<Uint8Array | null>;
10
+ set(privateKey: Uint8Array): void;
11
+ setAsync(privateKey: Uint8Array): Promise<void>;
12
+ provide(): Uint8Array;
13
+ provideAsync(): Promise<Uint8Array>;
14
+ removeAsync(): Promise<void>;
15
+ }
package/lib/entry.js ADDED
@@ -0,0 +1,49 @@
1
+ import { fromB64, toB64 } from '@sozai/codec';
2
+ import * as SecureStore from 'expo-secure-store';
3
+ import { randomPrivateKey, randomPrivateKeyAsync } from './utils.js';
4
+ export class ExpoKeyEntry {
5
+ #keyID;
6
+ #options;
7
+ constructor(keyID, options){
8
+ this.#keyID = keyID;
9
+ this.#options = options;
10
+ }
11
+ get keyID() {
12
+ return this.#keyID;
13
+ }
14
+ get() {
15
+ const privateKey = SecureStore.getItem(this.#keyID, this.#options);
16
+ return privateKey ? fromB64(privateKey) : null;
17
+ }
18
+ async getAsync() {
19
+ const privateKey = await SecureStore.getItemAsync(this.#keyID, this.#options);
20
+ return privateKey ? fromB64(privateKey) : null;
21
+ }
22
+ set(privateKey) {
23
+ SecureStore.setItem(this.#keyID, toB64(privateKey), this.#options);
24
+ }
25
+ async setAsync(privateKey) {
26
+ await SecureStore.setItemAsync(this.#keyID, toB64(privateKey), this.#options);
27
+ }
28
+ provide() {
29
+ const existing = this.get();
30
+ if (existing != null) {
31
+ return existing;
32
+ }
33
+ const privateKey = randomPrivateKey();
34
+ this.set(privateKey);
35
+ return privateKey;
36
+ }
37
+ async provideAsync() {
38
+ const existing = await this.getAsync();
39
+ if (existing != null) {
40
+ return existing;
41
+ }
42
+ const privateKey = await randomPrivateKeyAsync();
43
+ await this.setAsync(privateKey);
44
+ return privateKey;
45
+ }
46
+ async removeAsync() {
47
+ await SecureStore.deleteItemAsync(this.#keyID, this.#options);
48
+ }
49
+ }
@@ -0,0 +1,3 @@
1
+ import { type FullIdentity } from '@kokuin/token';
2
+ export declare function provideFullIdentity(keyID: string): FullIdentity;
3
+ export declare function provideFullIdentityAsync(keyID: string): Promise<FullIdentity>;
@@ -0,0 +1,57 @@
1
+ import { createFullIdentity } from '@kokuin/token';
2
+ import { getLogger } from '@sozai/log';
3
+ import { AttributeKeys, createTracer, SpanNames, withSpan, withSyncSpan } from '@sozai/otel';
4
+ import { ExpoKeyStore } from './store.js';
5
+ const tracer = createTracer('keystore.expo');
6
+ const logger = getLogger([
7
+ 'kokuin',
8
+ 'expo'
9
+ ]);
10
+ export function provideFullIdentity(keyID) {
11
+ return withSyncSpan(tracer, SpanNames.KEYSTORE_GET_OR_CREATE, {
12
+ attributes: {
13
+ [AttributeKeys.KEYSTORE_STORE_TYPE]: 'expo'
14
+ }
15
+ }, (span)=>{
16
+ const entry = ExpoKeyStore.entry(keyID);
17
+ const existing = entry.get();
18
+ if (existing != null) {
19
+ const identity = createFullIdentity(existing);
20
+ span.setAttribute(AttributeKeys.AUTH_DID, identity.id);
21
+ span.setAttribute(AttributeKeys.KEYSTORE_KEY_CREATED, false);
22
+ return identity;
23
+ }
24
+ const key = entry.provide();
25
+ const identity = createFullIdentity(key);
26
+ span.setAttribute(AttributeKeys.AUTH_DID, identity.id);
27
+ span.setAttribute(AttributeKeys.KEYSTORE_KEY_CREATED, true);
28
+ logger.info('New identity generated: {did}', {
29
+ did: identity.id
30
+ });
31
+ return identity;
32
+ });
33
+ }
34
+ export async function provideFullIdentityAsync(keyID) {
35
+ return withSpan(tracer, SpanNames.KEYSTORE_GET_OR_CREATE, {
36
+ attributes: {
37
+ [AttributeKeys.KEYSTORE_STORE_TYPE]: 'expo'
38
+ }
39
+ }, async (span)=>{
40
+ const entry = ExpoKeyStore.entry(keyID);
41
+ const existing = await entry.getAsync();
42
+ if (existing != null) {
43
+ const identity = createFullIdentity(existing);
44
+ span.setAttribute(AttributeKeys.AUTH_DID, identity.id);
45
+ span.setAttribute(AttributeKeys.KEYSTORE_KEY_CREATED, false);
46
+ return identity;
47
+ }
48
+ const key = await entry.provideAsync();
49
+ const identity = createFullIdentity(key);
50
+ span.setAttribute(AttributeKeys.AUTH_DID, identity.id);
51
+ span.setAttribute(AttributeKeys.KEYSTORE_KEY_CREATED, true);
52
+ logger.info('New identity generated: {did}', {
53
+ did: identity.id
54
+ });
55
+ return identity;
56
+ });
57
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Key store for React Native.
3
+ *
4
+ * ## Installation
5
+ *
6
+ * ```sh
7
+ * npm install @kokuin/expo
8
+ * ```
9
+ *
10
+ * @module expo-keystore
11
+ */
12
+ export { ExpoKeyEntry } from './entry.js';
13
+ export { provideFullIdentity, provideFullIdentityAsync } from './identity.js';
14
+ export { ExpoKeyStore } from './store.js';
15
+ export { randomPrivateKey, randomPrivateKeyAsync } from './utils.js';
package/lib/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Key store for React Native.
3
+ *
4
+ * ## Installation
5
+ *
6
+ * ```sh
7
+ * npm install @kokuin/expo
8
+ * ```
9
+ *
10
+ * @module expo-keystore
11
+ */ export { ExpoKeyEntry } from './entry.js';
12
+ export { provideFullIdentity, provideFullIdentityAsync } from './identity.js';
13
+ export { ExpoKeyStore } from './store.js';
14
+ export { randomPrivateKey, randomPrivateKeyAsync } from './utils.js';
package/lib/store.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { KeyStore } from '@kokuin/token';
2
+ import { ExpoKeyEntry } from './entry.js';
3
+ export declare const ExpoKeyStore: KeyStore<Uint8Array, ExpoKeyEntry>;
package/lib/store.js ADDED
@@ -0,0 +1,6 @@
1
+ import { ExpoKeyEntry } from './entry.js';
2
+ export const ExpoKeyStore = {
3
+ entry: (keyID, options)=>{
4
+ return new ExpoKeyEntry(keyID, options);
5
+ }
6
+ };
package/lib/utils.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function randomPrivateKey(): Uint8Array;
2
+ export declare function randomPrivateKeyAsync(): Promise<Uint8Array>;
package/lib/utils.js ADDED
@@ -0,0 +1,7 @@
1
+ import { getRandomBytes, getRandomBytesAsync } from 'expo-crypto';
2
+ export function randomPrivateKey() {
3
+ return getRandomBytes(32);
4
+ }
5
+ export function randomPrivateKeyAsync() {
6
+ return getRandomBytesAsync(32);
7
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@kokuin/expo",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "Key store for React Native",
6
+ "keywords": [
7
+ "cryptography",
8
+ "key-management",
9
+ "react-native",
10
+ "expo",
11
+ "storage"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/TairuFramework/kokuin",
16
+ "directory": "packages/expo"
17
+ },
18
+ "type": "module",
19
+ "main": "lib/index.js",
20
+ "types": "lib/index.d.ts",
21
+ "exports": {
22
+ ".": "./lib/index.js"
23
+ },
24
+ "files": [
25
+ "lib/*"
26
+ ],
27
+ "sideEffects": false,
28
+ "dependencies": {
29
+ "@sozai/codec": "^0.1.0",
30
+ "@sozai/log": "^0.1.0",
31
+ "@sozai/otel": "^0.1.0",
32
+ "expo-crypto": "^56.0.4",
33
+ "expo-secure-store": "^56.0.4",
34
+ "@kokuin/token": "^0.1.0"
35
+ },
36
+ "scripts": {
37
+ "build:clean": "del lib",
38
+ "build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
39
+ "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
40
+ "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
41
+ "test:types": "tsc --noEmit --skipLibCheck -p tsconfig.test.json",
42
+ "test:unit": "vitest run",
43
+ "test": "pnpm run test:types && pnpm run test:unit"
44
+ }
45
+ }