New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@socialgouv/e2esdk-client

Package Overview
Dependencies
Maintainers
2
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@socialgouv/e2esdk-client - npm Package Compare versions

Comparing version

to
1.0.0-beta.27

523

dist/index.d.ts

@@ -5,6 +5,44 @@ import { PermissionFlags } from '@socialgouv/e2esdk-api';

/**
* Configuration object for the e2esdk client constructor
*/
type ClientConfig<KeyType = string> = {
/**
* Fully qualified URL to the e2esdk server
*
* As found in the server's .env configuration, under `DEPLOYMENT_URL`.
*/
serverURL: string;
/**
* Serialised server signature public key
*
* As found in the server's .env configuration, under `SIGNATURE_PUBLIC_KEY`
* This is used to establish mutual authentication of API calls,
* so that the client can verify authenticity of responses coming
* from the server, and detect MitM tampering.
*/
serverSignaturePublicKey: KeyType;
/**
* Enable real-time sync with WebSockets for this instance
*
* This defaults to `true` for most cases where there is a single client
* instance in the application.
* Devtools have it set to false when creating their own client instance,
* in order to avoid feedback loops when local-syncing with the main client.
*/
handleNotifications?: boolean;
/**
* Enable automatic re-authentication on 401 Unauthorized API responses
*
* The default auth session TTL is short-lived (1 hour), so re-authentication
* is necessary, and can be automated using this flag.
* Upon reception of a 401 response status code, the client will attempt to
* login again to refresh its session, and retry the failed operation,
* up to 3 times, after which an error will be thrown.
*
* This defaults to true, and should follow the value of `handleNotifications`:
* true for one main client instance, and false for replicas.
*
* Devtools with their own client don't automatically re-authenticate on 401s.
*/
handleSessionRefresh?: boolean;

@@ -16,5 +54,5 @@ };

declare const keychainItemSchema: z.ZodObject<{
name: z.ZodString;
nameFingerprint: z.ZodString;
payloadFingerprint: z.ZodString;
keychainName: z.ZodString;
keychainFingerprint: z.ZodString;
keyFingerprint: z.ZodString;
cipher: z.ZodEffects<z.ZodString, {

@@ -36,5 +74,5 @@ publicKey: Uint8Array;

}, "strip", z.ZodTypeAny, {
name: string;
nameFingerprint: string;
payloadFingerprint: string;
keychainName: string;
keychainFingerprint: string;
keyFingerprint: string;
cipher: {

@@ -56,5 +94,5 @@ publicKey: Uint8Array;

}, {
name: string;
nameFingerprint: string;
payloadFingerprint: string;
keychainName: string;
keychainFingerprint: string;
keyFingerprint: string;
cipher: string;

@@ -66,6 +104,6 @@ createdAt: string;

type KeychainItem = z.infer<typeof keychainItemSchema>;
type KeychainItemMetadata = Pick<KeychainItem, 'nameFingerprint' | 'payloadFingerprint' | 'createdAt' | 'expiresAt' | 'sharedBy'> & {
type KeychainItemMetadata = Pick<KeychainItem, 'keychainFingerprint' | 'keyFingerprint' | 'createdAt' | 'expiresAt' | 'sharedBy'> & {
algorithm: Cipher['algorithm'];
publicKey?: string;
label: string;
purpose: string;
};

@@ -86,2 +124,19 @@ type PublicUserIdentity = {

};
/**
* The main e2esdk client interface
*
* This performs all the cryptographic operations required to implement E2EE
* in your application, along with a deployed server for persistance and
* coordination with other clients.
*
* It requires a little configuration to connect it to a running e2esdk server,
* and enable public-key based mutual authentication of API calls.
*
* Multiple clients instanciated on the same origin will sync their state:
* a successfull login on one will enable the others to perform actions,
* making multi-tab applications seamless.
*
* Clients react in real-time to server-sent events, and sync their keystore
* automatically. You can subscribe to events using the .on() method.
*/
declare class Client {

@@ -91,14 +146,123 @@ #private;

readonly config: Readonly<Config>;
/**
* Create a new instance of the e2esdk client
*
* This operation is generally safe to perform on the server in SSR contexts,
* however most other operations will require to run in a browser environment,
* and require authentication.
*
* @param config Client configuration object
*/
constructor(config: ClientConfig);
/**
* Subscribe to events
*
* @param event the event name to subscribe to, see available {@link Events}
* @param callback pass a callback function with the appropriate payload
* @returns an unsubscribe function, to be called to stop listening
*
* Example:
* ```ts
* // Subscribe to identity changes:
* const off = client.on('identityUpdated', identity => {
* if (identity) {
* console.log(identity.userId)
* } else {
* // logged out
* }
* })
* // Unsubscribe
* off()
* ```
*/
on<K extends keyof Events>(event: K, callback: (arg: Events[K]) => void): () => void;
/**
* Create an identity on e2esdk
*
* @param userId a unique, immutable identifier for a user in the application.
* Ideally, this should be an automatically generated primary key in the
* application database, like a UUID.
*
* This will do a couple of things:
* 1. Create an identity derived from a newly generated mainKey
* 2. Register a device pre-enrolled to this account
* 3. Persist those objects on the server
*
* Note that signup does not authenticate the user, you will need to call
* the `login` method after a successful signup to establish an authenticated
* session.
*/
signup(userId: string): Promise<void>;
/**
* Authenticate using the local enrolled device authentication
*
* @param userId The user ID used at registration (signup) time
* @returns A Promise to the public user identity if the login succeeds,
* or null if it fails.
*
* It may seem weird that only the userId is required to authenticate,
* but that's a side effect of using enrolled devices for access: the
* actual credentials are stored on each device, the user ID is only a
* way to handle multiple accounts on a single physical storage context
* (eg: alice & bob sharing the same Firefox browser).
*
* When logging in, the device credentials will be retrieved from
* local storage, and used to perform an OPAQUE authentication flow.
* Out of that, the OPAQUE export key will be used to unwrap the
* user account mainKey, from which the user identity will be derived.
* The OPAQUE key agreement also defines the session ID.
*
* Once the client is hydrated with an identity and a session ID, it can
* perform authenticated calls to the API.
*/
login(userId: string): Promise<PublicUserIdentity | null>;
/**
* Revoke the current authentication session
*
* This will clear all local state and lock up the client.
* A login step will be necessary to further resume authenticated operations.
*/
logout(): void;
/**
* On an active device, prepare to enroll another device.
*
* This will retrieve the user account mainKey, generate a set of OPAQUE
* credentials for the new device, perform an OPAQUE registration to obtain
* an export key, and wrap the mainKey with it. The credentials are then
* returned to the application to be transmitted to the new device for
* final registration.
*
* @see {@link registerEnrolledDevice `registerEnrolledDevice`}, to be
* called on the new device with the registration URI string returned by
* this method. Transmission is left to the application, though an offline
* delivery method (eg: scanning a QR code) is recommended.
*
* @authenticated This method requires authentication
*
* @param label Optional name to give the device, for later identification.
* Will be end-to-end encrypted when persisted on the server.
* @returns A Promise to a registration URI string to send to the enrolled device.
*/
enrollNewDevice(label?: string): Promise<string>;
/**
* Register this device and login
* @param uri device registration URI
*
* Registration means saving the given credentials into local storage,
* so that the login process can use them for authentication.
*
* In and out of itself, this method wouldn't do much, so it also attempts
* to login to establish a session, as it would be the next logical step.
*
* @param uri device registration URI, as obtained from a call to
* {@link enrollNewDevice `enrollNewDevice`} on the originating device.
*/
registerEnrolledDevice(uri: string): Promise<PublicUserIdentity | null>;
get currentDeviceId(): string | null;
/**
* Retrieve a list of currently enrolled devices for this account.
*
* Also includes active session information for each device.
*
* @authenticated This method requires authentication
*/
getEnrolledDevices(): Promise<{

@@ -114,16 +278,139 @@ label: string | undefined;

}[]>;
createKey(label: string, algorithm: 'secretBox' | 'sealedBox', expiresAt?: Date): Promise<KeychainItemMetadata>;
rotateKey(nameFingerprint: string, expiresAt?: Date): Promise<KeychainItemMetadata>;
/**
* Create a new keychain for a given purpose, with an initial key (or key pair)
*
* This will create a key of the given algorithm, and attach it to a new
* keychain, labelled with the given purpose.
*
* Note that two calls to this method with the same `purpose` will generate
* different keychains (different `keychainFingerprint` values).
*
* If you want to rotate an existing key, use {@link rotateKey `rotateKey`}.
*
* @param purpose What this keychain will be used for, to let your application
* retrieve it later.
* @param algorithm `secretBox` for symmetric encryption, `sealedBox` for form data.
* // todo: Add link to online docs that explains the difference
* @param expiresAt Optional expiration date for the initial key
*
* @authenticated This method requires authentication
*/
createNewKeychain(purpose: string, algorithm: 'secretBox' | 'sealedBox', expiresAt?: Date): Promise<KeychainItemMetadata>;
/**
* Add a new key to an existing keychain, replacing the older one
* for encryption operations.
*
* Previous keys remain available in the keychain for decryption operations.
*
* @param keychainFingerprint
* @param expiresAt Optional expiration date for the new key
*
* @authenticated This method requires authentication
*/
rotateKey(keychainFingerprint: string, expiresAt?: Date): Promise<KeychainItemMetadata>;
/**
* Get a record of available keys.
*
* @returns a record object keyed by the keychainFingerprint and whose values
* are arrays of keys, most recent first (the one used for encryption).
*
* @authenticated This accessor requires authentication
*/
get keys(): Record<string, KeychainItemMetadata[]>;
findKeyByNameFingerprint(nameFingerprint: string): KeychainItemMetadata | undefined;
findKeyByLabel(label: string): KeychainItemMetadata | undefined;
deleteKey(nameFingerprint: string, payloadFingerprint: string): Promise<void>;
shareKey(nameFingerprint: string, to: PublicUserIdentity, { expiresAt }?: ShareKeyOptions): Promise<void>;
/**
* Find the most recent key (to use for encryption) for a given keychainFingerprint.
*
* Server-provided data uses the keychainFingerprint to identify purposes,
* so this method can be used to retrieve a key based on that data.
*
* @authenticated This method requires authentication
* (will return `undefined` if unauthenticated)
*/
findKeyByKeychainFingerprint(keychainFingerprint: string): KeychainItemMetadata | undefined;
/**
* Find the most recent key (to use for encryption) for a given purpose.
*
* @authenticated This method requires authentication
* (will return `undefined` if unauthenticated)
*/
findKeyByPurpose(purpose: string): KeychainItemMetadata | undefined;
/**
* Delete a specific key
*
* This will remove it both on the client's keychain and erase its record
* on the server, and sync up other devices and clients for this user.
*
* @authenticated This method requires authentication
*
*/
deleteKey(keychainFingerprint: string, keyFingerprint: string): Promise<void>;
/**
* Share only the most recent key in the given keychain with another e2esdk user.
*
* To share a specific key in a specific keychain, use {@link shareKey `shareKey`}.
* To share the whole keychain, use {@link shareCompleteKeychain `shareCompleteKeychain`}.
*
* @param keychainFingerprint keychain to share (only the latest key)
* @param shareWith Public identity of the user to share the key with
* (only the user ID and sharing public key are required)
* @param options Optional bag of options (key expiration, etc..)
*
* @authenticated This method requires authentication
*/
shareMostRecentKey(keychainFingerprint: string, shareWith: Pick<PublicUserIdentity, 'userId' | 'sharingPublicKey'>, options?: ShareKeyOptions): Promise<void>;
/**
* Share all the keys available in a keychain with another e2esdk user.
*
* This may be useful to give complete access to a newcoming user in a
* shared workspace.
*
* Note however that only the keys you possess will be shared. If other users
* have a more extended keychain, their extra keys won't be shared.
*
* @param keychainFingerprint keychain to send to the user
* @param shareWith Public identity of the user to share the key with
* (only the user ID and sharing public key are required)
* @param options Optional bag of options (key expiration, etc..)
*
* @authenticated This method requires authentication
*/
shareCompleteKeychain(keychainFingerprint: string, shareWith: Pick<PublicUserIdentity, 'userId' | 'sharingPublicKey'>, options?: ShareKeyOptions): Promise<void>;
/**
* Share a specific key in a specific keychain with a specific e2esdk user.
*
* To share the latest key in a specific keychain, use {@link shareMostRecentKey `shareMostRecentKey`}.
* To share the whole keychain, use {@link shareCompleteKeychain `shareCompleteKeychain`}.
*
* @param keychainFingerprint keychain where to find the key
* @param keyFingerprint fingerprint of the key to share
* @param shareWith Public identity of the user to share the key with
* (only the user ID and sharing public key are required)
* @param options Optional bag of options (key expiration, etc..)
*
* @authenticated This method requires authentication
*/
shareKey(keychainFingerprint: string, keyFingerprint: string, shareWith: Pick<PublicUserIdentity, 'userId' | 'sharingPublicKey'>, { expiresAt }?: ShareKeyOptions): Promise<void>;
/**
* List pending shared keys from this user to others
*
* @authenticated This method requires authentication
*/
getOutgoingSharedKeys(): Promise<{
createdAt: string;
nameFingerprint: string;
expiresAt: string | null;
name: string;
payload: string;
payloadFingerprint: string;
keychainFingerprint: string;
expiresAt: string | null; /**
* Register this device and login
*
* Registration means saving the given credentials into local storage,
* so that the login process can use them for authentication.
*
* In and out of itself, this method wouldn't do much, so it also attempts
* to login to establish a session, as it would be the next logical step.
*
* @param uri device registration URI, as obtained from a call to
* {@link enrollNewDevice `enrollNewDevice`} on the originating device.
*/
encryptedKeychainName: string;
encryptedKey: string;
keyFingerprint: string;
signature: string;

@@ -136,7 +423,46 @@ toUserId: string;

}[]>;
deleteOutgoingSharedKey(toUserId: string, payloadFingerprint: string): Promise<void>;
/**
* Cancel sharing a key with someone else
*
* @authenticated This method requires authentication
*/
deleteOutgoingSharedKey(toUserId: string, keyFingerprint: string): Promise<void>;
/**
* Get the identity of the currently logged-in user, or `null` if unauthenticated.
*/
get publicIdentity(): PublicUserIdentity | null;
/**
* Obtain the identity of a particular user
*
* This will ask the server for the public record of identity for the given
* userId, and verify its proof.
*
* To lookup multiple users at once, use {@link getUsersIdentities `getUserIdentities`}.
*
* @param userId The user ID to lookup
* @returns a Promise to the identity, or `null` if not found or invalid proof.
*
* @authenticated This method requires authentication
*/
getUserIdentity(userId: string): Promise<PublicUserIdentity | null>;
/**
* Lookup multiple user identities in one go.
*
* To lookup a single user, use {@link getUserIdentity `getUserIdentity`}.
*
* @param userIds a list of user ID to lookup
*
* @authenticated This method requires authentication
*/
getUsersIdentities(userIds: string[]): Promise<PublicUserIdentity[]>;
getParticipants(nameFingerprint: string, payloadFingerprint: string): Promise<{
/**
* List users with access to a given key
*
* @param keychainFingerprint keychain fingerprint to lookup
* @param keyFingerprint fingerprint of a particular key in the keychain
* @returns an array of identities, permissions and other metadata
*
* @authenticated This method requires authentication
*/
getParticipants(keychainFingerprint: string, keyFingerprint: string): Promise<{
userId: string;

@@ -153,3 +479,10 @@ sharingPublicKey: string;

}[]>;
getPermissions(nameFingerpint: string): Promise<{
/**
* Get your own permissions for a given keychain
*
* @param keychainFingerprint keychain fingerprint to lookup
*
* @authenticated This method requires authentication
*/
getPermissions(keychainFingerprint: string): Promise<{
allowSharing: boolean;

@@ -160,10 +493,138 @@ allowRotation: boolean;

}>;
setPermissions(userId: string, nameFingerprint: string, permissions: Partial<PermissionFlags>): Promise<void>;
banUser(userId: string, nameFingerprint: string): Promise<void>;
encrypt<DataType>(input: DataType, nameFingerprint: string, additionalData?: string | Uint8Array): string;
decrypt(ciphertext: string, nameFingerpint: string, additionalData?: string | Uint8Array): unknown;
unsealFormData<FormData extends object>(submission: EncryptedFormSubmission<FormData>, nameFingerpint: string): Record<keyof FormData, unknown>;
/**
* Change permissions for another participant of a keychain
*
* This call will succeed only if you have the `allowManagement` permission
* for the given keychain.
* Note that you may apply permissions to yourself as well, including
* revoking your `allowManagement` permission. If no other participant has
* this right, permissions won't be able to be changed!
*
* @param userId User ID for whom to set permissions
* @param keychainFingerprint Keychain fingerprint to apply the permissions to
* @param permissions Partial object with boolean permissions to apply
*
* @authenticated This method requires authentication
*/
setPermissions(userId: string, keychainFingerprint: string, permissions: Partial<PermissionFlags>): Promise<void>;
/**
* Revoke access to the given keychain for a user.
*
* This requires the `allowDeletion` permission on the keychain
* for the calling user.
*
* You can always ban yourself off of a keychain, regardless of permissions,
* to allow cleaning up. Use this to remove all traces of a keychain
* from your account.
*
* Note: banning does **not** perform key rotation.
* If banning a user for security reasons, it is recommended to rotate
* the current encryption key for all other remaining participants.
*
* The workflow is as such:
* 1. Ban the user from the keychain using this method
* 2. Rotate the key using {@link rotateKey}
* 3. Obtain the list of participants for the keychain with {@link getParticipants}
* 4. Share the latest key with the remaining participants using {@link shareMostRecentKey}
*
* @param userId user ID to ban
* @param keychainFingerprint keychain fingerprint to remove access to
*
* @authenticated This method requires authentication
*/
banUser(userId: string, keychainFingerprint: string): Promise<void>;
/**
* Encrypt arbitrary data
*
* The algorithm will depend upon the keychain type, though this is mostly
* useful for symmetric cryptography, using `secretBox` keys.
*
* @param input arbitrary data
* (strings, numbers, objects, arrays, as long as it's JSON-serialisable)
* @param keychainFingerprint which keychain to use for encryption
* (the most recent key will be used)
* @param additionalData Extra authenticated data that is not encrypted, but
* that must be presented as-is for decryption to succeed.
* This allows binding the ciphertext to a particular context.
* See https://en.wikipedia.org/wiki/Authenticated_encryption
* @returns a string containing the encoded ciphertext and metadata
*
* @authenticated This method requires authentication
*/
encrypt<DataType>(input: DataType, keychainFingerprint: string, additionalData?: string | Uint8Array): string;
/**
* Decrypt arbitrary data
*
* Note: to decrypt form data, use {@link unsealFormData `unsealFormData`}.
*
* This will try decrypting a given ciphertext string against all available
* keys in the specified keychain. If all keys are exhausted without success,
* an error will be thrown.
*
* @param input arbitrary data
* (strings, numbers, objects, arrays, as long as it's JSON-serialisable)
* @param keychainFingerprint which keychain to use for encryption
* (the most recent key will be used)
* @param additionalData Extra authenticated data that was not encrypted, but
* that must be presented as-is for decryption to succeed.
* This allows binding the ciphertext to a particular context.
* See https://en.wikipedia.org/wiki/Authenticated_encryption
* @returns an unknown type: you must pass this through a parser that ensures
* the clear text data conforms to a specific type, in order to prevent
* from untrusted inputs.
*
* @authenticated This method requires authentication
*/
decrypt(ciphertext: string, keychainFingerprint: string, additionalData?: string | Uint8Array): unknown;
/**
* Decrypt form data encrypted with `encryptFormData`.
*
* @param submission encrypted form data & associated cryptographic metadata
* @param keychainFingerprint keychain to use for decryption
* @returns a record of unknown values: you must pass the result through a
* parser that ensures form data conforms to a specific type, to avoid and
* reject untrusted / malformed data submissions.
*
* @authenticated This method requires authentication
*/
unsealFormData<FormData extends object>(submission: EncryptedFormSubmission<FormData>, keychainFingerprint: string): Record<keyof FormData, unknown>;
/**
* Sign an arbitrary array of string items against the user's identity
*
* This should be used with care, especially if dealing with untrusted
* user-provided inputs, even though the underlying signature algorithm
* has protections against canonicalization attacks.
*
* Note: the order of items must be the same for signature and verification!
*
* @param items List of items to generate a signature for
* @returns a base64url-encoded signature string
*
* @authenticated This method requires authentication
*/
sign(...items: string[]): string;
/**
* Verify the signature of an arbitrary array of string items
* against a given user's identity.
*
* This should be used with care, especially if dealing with untrusted
* user-provided inputs, even though the underlying signature algorithm
* has protections against canonicalization attacks.
*
* Note: the order of items must be the same for signature and verification!
*
* @param signature Signature string as obtained from {@link sign `sign`}.
* @param publicKey Signature public key of the alleged author
* (part of the public identity). Can be provided as base64url or byte array.
* @param items List of items to verify the signature against
* @returns true if the signature is valid, false otherwise.
*/
verifySignature(signature: string, publicKey: string | Uint8Array, ...items: string[]): boolean;
/**
* Encode the input byte array to base64url
*/
encode(input: Uint8Array): string;
/**
* Decode a base64url-encoded string into a byte array
*/
decode(input: string): Uint8Array;

@@ -170,0 +631,0 @@ }

6

package.json
{
"name": "@socialgouv/e2esdk-client",
"version": "1.0.0-beta.26",
"version": "1.0.0-beta.27",
"license": "Apache-2.0",

@@ -44,4 +44,4 @@ "description": "End-to-end encryption client",

"@47ng/opaque-client": "^2.1.5",
"@socialgouv/e2esdk-api": "^1.0.0-beta.12",
"@socialgouv/e2esdk-crypto": "^1.0.0-beta.18",
"@socialgouv/e2esdk-api": "^1.0.0-beta.13",
"@socialgouv/e2esdk-crypto": "^1.0.0-beta.19",
"local-state-sync": "1.0.0-beta.6",

@@ -48,0 +48,0 @@ "mitt": "^3.0.0",

@@ -1,1 +0,1 @@

{"$schema":"https://raw.githubusercontent.com/47ng/sceau/main/src/schemas/v1.schema.json","signature":"405f3c08044c4ad4200d184e225840cacd9cda6f529789e0f7d4898ec21bcafa4d34f747eb2806beed7e19de8224b5f68ee737d584c86099be080f853bb73e08","publicKey":"82182691aa16fb18c4ee5f502f9067fe486768391d6ad5baa95e7a68913c9ad9","timestamp":"2023-05-12T08:08:54.595Z","sourceURL":"https://github.com/SocialGouv/e2esdk/tree/7011205faaa59271f150aa45152d4d10f59dc788","buildURL":"https://github.com/SocialGouv/e2esdk/actions/runs/4956565442","manifest":[{"path":"README.md","hash":"4d045827bb62a85317c226a17beb8fcced4f7464c9cd98b1a9f5454f189d6a5e41da42f1b52183dfe66f166371e9caafb80f170af967d8c7b8999fecd6751c0b","sizeBytes":184,"signature":"73db42e6419b8c7b628e73c87229c182557c258a4ec4ed8a270cb01658fbf7b8d1289288d543bf6a8ec85c9f3836ef8d70f7cba18b38604b128b3973d5bcd009"},{"path":"dist/index.cjs","hash":"20bdd18f37fae1b3ebe591bb98bb375edd0c3ce5984dde8ec9b0f3f45bd463360ede7c4be71c8c55ec0de7d3c72f02edb8b6fe51155afa4ebba973471a48f32d","sizeBytes":48594,"signature":"0951700c9a7a230c73145d71a9ecf970f70b36ac8d58697f5e5722c0ae044cae5f32cc3bfc892d30892abb02a270c3ea191513c14f91178ffe3d2865e0872109"},{"path":"dist/index.d.ts","hash":"fed6d92f381f2293fdcea02490e975a2f821d0db419efa7551c4514490a35e2135d97e785ee9a58a58be3bc89134d07c9c095e6fc16983d907d002f6b04dfca0","sizeBytes":6182,"signature":"3195092302f3c0f0703fa11502c31106a09a6c772ae305afa0d599b851e5973f5448dcd29f71701c613a2e00dc480ae3275bc6063b42caa72074190ea027510e"},{"path":"dist/index.js","hash":"ec640a1d0cec4b22e9a24fbee1f43c6ab825d70e7167d5c791d4097d501b8e340a85ed8af0fccc5281416b7ad8780e7f2e31cab75402af114577c6b250f98501","sizeBytes":47304,"signature":"45b5c43357aa0e30b6c22311d61fe74c55589e2594422ec6b716417c38609a9ec13613a225216e9bf4443e6820d6b69288301cbb45fde10f02d5af22537a8702"},{"path":"package.json","hash":"5763211cef817029540d7d140873c09c54c48caeefddc35234f1003a88064d653e15a65e210f4cd0fbc0382c2e3970257e6768425952498cbccdde307099050b","sizeBytes":1352,"signature":"54614dbfbcfec768ac14b5e56f18c26d35c84220240f715119870b0fca3ec6638139bd518cac302a0a789984f01d9ded26ceedefaa6f8cd1b965674c75c52204"}]}
{"$schema":"https://raw.githubusercontent.com/47ng/sceau/main/src/schemas/v1.schema.json","signature":"01b9d4d1923c506e5935a2b3d4c83df0fce0c14eb0d9383e3965e5fa714054dfcb5af68e2d4e9058885f0ffe5090d5070a2909468a77b2c4c4e8b9ca4980c60c","publicKey":"82182691aa16fb18c4ee5f502f9067fe486768391d6ad5baa95e7a68913c9ad9","timestamp":"2023-06-09T08:57:38.224Z","sourceURL":"https://github.com/SocialGouv/e2esdk/tree/5541d404ad8df976dc9ccfba1305ad0d20648004","buildURL":"https://github.com/SocialGouv/e2esdk/actions/runs/5220055014","manifest":[{"path":"README.md","hash":"4d045827bb62a85317c226a17beb8fcced4f7464c9cd98b1a9f5454f189d6a5e41da42f1b52183dfe66f166371e9caafb80f170af967d8c7b8999fecd6751c0b","sizeBytes":184,"signature":"73db42e6419b8c7b628e73c87229c182557c258a4ec4ed8a270cb01658fbf7b8d1289288d543bf6a8ec85c9f3836ef8d70f7cba18b38604b128b3973d5bcd009"},{"path":"dist/index.cjs","hash":"ef4d9761b966ff95499b96b86565c0dd210caf4879f30043667f8e6466c0b58d42541ef24126885ef8dd8bfc084be5d540e4cbc911b4b8d89faf384c641a762a","sizeBytes":67418,"signature":"bb8cac21c44ba4444c39b13684484701371d0e8eef7e305173d33e4dd0e9339896d143352670852a9d1c4fecf83851165ffeb3d0bd2ff87e90d381cf19a2d10c"},{"path":"dist/index.d.ts","hash":"084de89f3e91dfccbe9c82dcaf888460f67a0ecedf54eb75d6abd1f4f7520819bd7747045c8191e9ca3cce757c91384b60f41371969409e2250951e4310b0150","sizeBytes":26114,"signature":"5a64446eb1909e66785357e808e4774022bf1b654a7cdfedfad2a50b21a3db8bc6bc9d0d3c2d23ba06035b1472fe95a05721e66263686513ab930f04816c4805"},{"path":"dist/index.js","hash":"de1b2f0355dcbe51752cd0213501dc389e2483cf919697950518c694e5f246d41f0df61eb62c2fbc9e58fedd1de90e095d7a8cbd5ba9feba1f1b4278b0b6328a","sizeBytes":65894,"signature":"4c363f502643f98bea84925b2f8e6a4f0318065f2a8b2650d6e64040be460225562de4611bd37a5ab889f90e8eaafdc9e9c4de1c94cb971be9f7178851224d0c"},{"path":"package.json","hash":"320678ad3270a8c4975c5f5bd900ef42a688442b932ce23c099d30f2c54edf0a43028c2168706eefddf735f8b75b433404a9a64100eee92f9d04792650f42370","sizeBytes":1352,"signature":"15ae0d691018030c2d3e47050cb14031cd8223ee3a88f04af6b870480230e64c2fadbb374554ae8fc6d1fa5c046fde66ec2127d94250021b72bb2abcc2ed8d05"}]}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display