Skip to content

feat: save ln address as contact #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Jul 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c6c3c6e
feat(core): add ContactsRepository with persist, find and update methods
esaugomez31 Apr 28, 2025
6366a2f
chore(core|services): repository function requesting object parameters
esaugomez31 Apr 29, 2025
5011aea
chore: refactored contact collection
esaugomez31 Apr 30, 2025
4f53a40
feat: graphql accountContactUpsert mutation, initial version
esaugomez31 Apr 30, 2025
757d023
chore: file to updated and add contact renamed
esaugomez31 Apr 30, 2025
3f160cd
refactor: move contact storage from accounts collection to dedicated …
esaugomez31 May 7, 2025
325275b
feat(core): migrate-contacts-to-collection
esaugomez31 May 8, 2025
dacd20c
test(core|e2e): test upsert contact mutation
esaugomez31 May 8, 2025
01d3c60
chore: remove personal data
esaugomez31 May 8, 2025
599c4ea
chore: renaming mutation accountContactUpsert to contactCreate
esaugomez31 May 9, 2025
6efa7d7
chore: renamin contact with upsert references
esaugomez31 May 9, 2025
fe7d51c
refactor: referencing the contacts collection in accounts object
esaugomez31 May 12, 2025
a968a8e
refactor(account): remove contacts field from Account schema
esaugomez31 May 14, 2025
7667353
fix(migrations): avoid redeclaration of randomUUID in contact to coll…
esaugomez31 Jun 17, 2025
8667b34
refactor(graphql): rename Contact.identifier to handle and Contact.al…
esaugomez31 Jun 19, 2025
c980cea
refactor(contacts): clean schema and rename repository methods
esaugomez31 Jun 23, 2025
b55307c
refactor(contacts): clean up embedded contacts after migration
esaugomez31 Jun 23, 2025
804e6af
refactor(graphql): rename contact-create.ts to contact.ts to match ob…
esaugomez31 Jun 23, 2025
719b075
refactor(contacts): unify contact creation logic and align with app c…
esaugomez31 Jun 24, 2025
7c79dd2
refactor(account): remove contact query from translateToAccount
esaugomez31 Jun 24, 2025
dd6c3fe
chore(e2e): clean test description to contacts
esaugomez31 Jul 2, 2025
a888749
chore(migration): move contacts unset operation to separate migration
esaugomez31 Jul 3, 2025
9bc3afa
refactor(domain): unify handle validation and remove casts from domai…
esaugomez31 Jul 3, 2025
3a717b0
fix: using handle type to contacts vars
esaugomez31 Jul 7, 2025
751a1fd
chore: remove migration of unset contacts to a separate pr
esaugomez31 Jul 7, 2025
dcace3a
refactor(contacts): rename validation functions and enhance contact e…
esaugomez31 Jul 17, 2025
9307158
fix: solve graphql generated file conflicts
esaugomez31 Jul 17, 2025
4e35527
feat(core): contact ValidationInternalError to error-map
esaugomez31 Jul 23, 2025
e2a097f
refactor(core): use accountId in getContactByHandle
esaugomez31 Jul 23, 2025
8301e9f
test(e2e): update is_contact helper to use same contacts query as bli…
esaugomez31 Jul 24, 2025
f47d566
refactor: deprecate username and include handle in AccountContact res…
esaugomez31 Jul 24, 2025
ac1cc91
fix: update contact repository interface
dolcalmi Jul 31, 2025
b7d826d
fix: contact payload name
dolcalmi Jul 31, 2025
466b47d
fix: contact display name default value
dolcalmi Jul 31, 2025
dcef2cc
fix: remove toLightningAddress
dolcalmi Jul 31, 2025
44956a4
fix: use 1 param rule in getContactsByAccountId
dolcalmi Jul 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions apps/consent/app/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export type Scalars = {
CentAmount: { input: number; output: number; }
/** An alias name that a user can set for a wallet (with which they have transactions) */
ContactAlias: { input: string; output: string; }
/** A display name that a user can assign to a contact */
ContactDisplayName: { input: string; output: string; }
/** Unique handle used to identify a contact (e.g., username or lnAddress) */
ContactHandle: { input: string; output: string; }
/** Unique identifier of a contact */
ContactId: { input: string; output: string; }
/** A CCA2 country code (ex US, FR, etc) */
CountryCode: { input: string; output: string; }
/** Display currency of an account */
Expand Down Expand Up @@ -418,6 +424,40 @@ export type ConsumerAccountWalletByIdArgs = {
walletId: Scalars['WalletId']['input'];
};

export type Contact = {
readonly __typename: 'Contact';
/** Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) */
readonly createdAt: Scalars['Timestamp']['output'];
/** DisplayName name the user assigns to the contact. */
readonly displayName?: Maybe<Scalars['ContactDisplayName']['output']>;
/** Username or lnAddress that identifies the contact. */
readonly handle: Scalars['ContactHandle']['output'];
/** ID of the contact user or external handle. */
readonly id: Scalars['ContactId']['output'];
/** Total number of transactions with this contact. */
readonly transactionsCount: Scalars['Int']['output'];
/** Type of the contact (intraledger, lnaddress, etc.). */
readonly type: ContactType;
};

export type ContactCreateInput = {
readonly displayName?: InputMaybe<Scalars['ContactAlias']['input']>;
readonly handle?: InputMaybe<Scalars['ContactHandle']['input']>;
readonly type: ContactType;
};

export type ContactPayload = {
readonly __typename: 'ContactPayload';
readonly contact?: Maybe<Contact>;
readonly errors: ReadonlyArray<Error>;
};

export const ContactType = {
Intraledger: 'INTRALEDGER',
Lnaddress: 'LNADDRESS'
} as const;

export type ContactType = typeof ContactType[keyof typeof ContactType];
export type Coordinates = {
readonly __typename: 'Coordinates';
readonly latitude: Scalars['Float']['output'];
Expand Down Expand Up @@ -900,6 +940,7 @@ export type Mutation = {
readonly callbackEndpointDelete: SuccessPayload;
readonly captchaCreateChallenge: CaptchaCreateChallengePayload;
readonly captchaRequestAuthCode: SuccessPayload;
readonly contactCreate: ContactPayload;
readonly deviceNotificationTokenCreate: SuccessPayload;
readonly feedbackSubmit: SuccessPayload;
/**
Expand Down Expand Up @@ -1062,6 +1103,11 @@ export type MutationCaptchaRequestAuthCodeArgs = {
};


export type MutationContactCreateArgs = {
input: ContactCreateInput;
};


export type MutationDeviceNotificationTokenCreateArgs = {
input: DeviceNotificationTokenCreateInput;
};
Expand Down Expand Up @@ -1962,11 +2008,16 @@ export type UserContact = {
* Only the user can see the alias attached to their contact.
*/
readonly alias?: Maybe<Scalars['ContactAlias']['output']>;
readonly id: Scalars['Username']['output'];
/** Identifier of the contact (username or Lightning address). */
readonly handle: Scalars['ContactHandle']['output'];
readonly id: Scalars['ContactHandle']['output'];
/** Paginated list of transactions sent to/from this contact. */
readonly transactions?: Maybe<TransactionConnection>;
readonly transactionsCount: Scalars['Int']['output'];
/** Actual identifier of the contact. */
/**
* Actual identifier of the contact. Deprecated: use `handle` instead.
* @deprecated Use `handle` field; this will be removed in a future release.
*/
readonly username: Scalars['Username']['output'];
};

Expand Down
5 changes: 5 additions & 0 deletions apps/consent/codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ generates:
EndpointUrl: "string"
Object: "string"
NotificationCategory: "string"
AccountId: "string"
ContactId: "string"
ContactHandle: "string"
ContactType: "string"
ContactDisplayName: "string"
5 changes: 5 additions & 0 deletions apps/dashboard/codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ generates:
EndpointUrl: "string"
NotificationCategory: "string"
DateTime: "string"
AccountId: "string"
ContactId: "string"
ContactHandle: "string"
ContactType: "string"
ContactDisplayName: "string"
105 changes: 102 additions & 3 deletions apps/dashboard/services/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export type Scalars = {
CentAmount: { input: number; output: number; }
/** An alias name that a user can set for a wallet (with which they have transactions) */
ContactAlias: { input: string; output: string; }
/** A display name that a user can assign to a contact */
ContactDisplayName: { input: string; output: string; }
/** Unique handle used to identify a contact (e.g., username or lnAddress) */
ContactHandle: { input: string; output: string; }
/** Unique identifier of a contact */
ContactId: { input: string; output: string; }
/** A CCA2 country code (ex US, FR, etc) */
CountryCode: { input: string; output: string; }
/** Display currency of an account */
Expand Down Expand Up @@ -458,6 +464,40 @@ export type ConsumerAccountWalletByIdArgs = {
walletId: Scalars['WalletId']['input'];
};

export type Contact = {
readonly __typename: 'Contact';
/** Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) */
readonly createdAt: Scalars['Timestamp']['output'];
/** DisplayName name the user assigns to the contact. */
readonly displayName?: Maybe<Scalars['ContactDisplayName']['output']>;
/** Username or lnAddress that identifies the contact. */
readonly handle: Scalars['ContactHandle']['output'];
/** ID of the contact user or external handle. */
readonly id: Scalars['ContactId']['output'];
/** Total number of transactions with this contact. */
readonly transactionsCount: Scalars['Int']['output'];
/** Type of the contact (intraledger, lnaddress, etc.). */
readonly type: ContactType;
};

export type ContactCreateInput = {
readonly displayName?: InputMaybe<Scalars['ContactAlias']['input']>;
readonly handle?: InputMaybe<Scalars['ContactHandle']['input']>;
readonly type: ContactType;
};

export type ContactPayload = {
readonly __typename: 'ContactPayload';
readonly contact?: Maybe<Contact>;
readonly errors: ReadonlyArray<Error>;
};

export const ContactType = {
Intraledger: 'INTRALEDGER',
Lnaddress: 'LNADDRESS'
} as const;

export type ContactType = typeof ContactType[keyof typeof ContactType];
export type Coordinates = {
readonly __typename: 'Coordinates';
readonly latitude: Scalars['Float']['output'];
Expand Down Expand Up @@ -997,6 +1037,7 @@ export type Mutation = {
readonly callbackEndpointDelete: SuccessPayload;
readonly captchaCreateChallenge: CaptchaCreateChallengePayload;
readonly captchaRequestAuthCode: SuccessPayload;
readonly contactCreate: ContactPayload;
readonly deviceNotificationTokenCreate: SuccessPayload;
readonly feedbackSubmit: SuccessPayload;
/**
Expand Down Expand Up @@ -1170,6 +1211,11 @@ export type MutationCaptchaRequestAuthCodeArgs = {
};


export type MutationContactCreateArgs = {
input: ContactCreateInput;
};


export type MutationDeviceNotificationTokenCreateArgs = {
input: DeviceNotificationTokenCreateInput;
};
Expand Down Expand Up @@ -2151,11 +2197,16 @@ export type UserContact = {
* Only the user can see the alias attached to their contact.
*/
readonly alias?: Maybe<Scalars['ContactAlias']['output']>;
readonly id: Scalars['Username']['output'];
/** Identifier of the contact (username or Lightning address). */
readonly handle: Scalars['ContactHandle']['output'];
readonly id: Scalars['ContactHandle']['output'];
/** Paginated list of transactions sent to/from this contact. */
readonly transactions?: Maybe<TransactionConnection>;
readonly transactionsCount: Scalars['Int']['output'];
/** Actual identifier of the contact. */
/**
* Actual identifier of the contact. Deprecated: use `handle` instead.
* @deprecated Use `handle` field; this will be removed in a future release.
*/
readonly username: Scalars['Username']['output'];
};

Expand Down Expand Up @@ -3558,7 +3609,14 @@ export type ResolversTypes = {
CentAmount: ResolverTypeWrapper<Scalars['CentAmount']['output']>;
CentAmountPayload: ResolverTypeWrapper<Omit<CentAmountPayload, 'errors'> & { errors: ReadonlyArray<ResolversTypes['Error']> }>;
ConsumerAccount: ResolverTypeWrapper<Omit<ConsumerAccount, 'callbackEndpoints' | 'invoices' | 'limits' | 'pendingIncomingTransactions' | 'transactions' | 'walletById' | 'wallets'> & { callbackEndpoints: ReadonlyArray<ResolversTypes['CallbackEndpoint']>, invoices?: Maybe<ResolversTypes['InvoiceConnection']>, limits: ResolversTypes['AccountLimits'], pendingIncomingTransactions: ReadonlyArray<ResolversTypes['Transaction']>, transactions?: Maybe<ResolversTypes['TransactionConnection']>, walletById: ResolversTypes['Wallet'], wallets: ReadonlyArray<ResolversTypes['Wallet']> }>;
Contact: ResolverTypeWrapper<Contact>;
ContactAlias: ResolverTypeWrapper<Scalars['ContactAlias']['output']>;
ContactCreateInput: ContactCreateInput;
ContactDisplayName: ResolverTypeWrapper<Scalars['ContactDisplayName']['output']>;
ContactHandle: ResolverTypeWrapper<Scalars['ContactHandle']['output']>;
ContactId: ResolverTypeWrapper<Scalars['ContactId']['output']>;
ContactPayload: ResolverTypeWrapper<Omit<ContactPayload, 'errors'> & { errors: ReadonlyArray<ResolversTypes['Error']> }>;
ContactType: ContactType;
Coordinates: ResolverTypeWrapper<Coordinates>;
Float: ResolverTypeWrapper<Scalars['Float']['output']>;
Country: ResolverTypeWrapper<Country>;
Expand Down Expand Up @@ -3790,7 +3848,13 @@ export type ResolversParentTypes = {
CentAmount: Scalars['CentAmount']['output'];
CentAmountPayload: Omit<CentAmountPayload, 'errors'> & { errors: ReadonlyArray<ResolversParentTypes['Error']> };
ConsumerAccount: Omit<ConsumerAccount, 'callbackEndpoints' | 'invoices' | 'limits' | 'pendingIncomingTransactions' | 'transactions' | 'walletById' | 'wallets'> & { callbackEndpoints: ReadonlyArray<ResolversParentTypes['CallbackEndpoint']>, invoices?: Maybe<ResolversParentTypes['InvoiceConnection']>, limits: ResolversParentTypes['AccountLimits'], pendingIncomingTransactions: ReadonlyArray<ResolversParentTypes['Transaction']>, transactions?: Maybe<ResolversParentTypes['TransactionConnection']>, walletById: ResolversParentTypes['Wallet'], wallets: ReadonlyArray<ResolversParentTypes['Wallet']> };
Contact: Contact;
ContactAlias: Scalars['ContactAlias']['output'];
ContactCreateInput: ContactCreateInput;
ContactDisplayName: Scalars['ContactDisplayName']['output'];
ContactHandle: Scalars['ContactHandle']['output'];
ContactId: Scalars['ContactId']['output'];
ContactPayload: Omit<ContactPayload, 'errors'> & { errors: ReadonlyArray<ResolversParentTypes['Error']> };
Coordinates: Coordinates;
Float: Scalars['Float']['output'];
Country: Country;
Expand Down Expand Up @@ -4203,10 +4267,38 @@ export type ConsumerAccountResolvers<ContextType = any, ParentType extends Resol
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type ContactResolvers<ContextType = any, ParentType extends ResolversParentTypes['Contact'] = ResolversParentTypes['Contact']> = {
createdAt?: Resolver<ResolversTypes['Timestamp'], ParentType, ContextType>;
displayName?: Resolver<Maybe<ResolversTypes['ContactDisplayName']>, ParentType, ContextType>;
handle?: Resolver<ResolversTypes['ContactHandle'], ParentType, ContextType>;
id?: Resolver<ResolversTypes['ContactId'], ParentType, ContextType>;
transactionsCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
type?: Resolver<ResolversTypes['ContactType'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export interface ContactAliasScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactAlias'], any> {
name: 'ContactAlias';
}

export interface ContactDisplayNameScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactDisplayName'], any> {
name: 'ContactDisplayName';
}

export interface ContactHandleScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactHandle'], any> {
name: 'ContactHandle';
}

export interface ContactIdScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactId'], any> {
name: 'ContactId';
}

export type ContactPayloadResolvers<ContextType = any, ParentType extends ResolversParentTypes['ContactPayload'] = ResolversParentTypes['ContactPayload']> = {
contact?: Resolver<Maybe<ResolversTypes['Contact']>, ParentType, ContextType>;
errors?: Resolver<ReadonlyArray<ResolversTypes['Error']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type CoordinatesResolvers<ContextType = any, ParentType extends ResolversParentTypes['Coordinates'] = ResolversParentTypes['Coordinates']> = {
latitude?: Resolver<ResolversTypes['Float'], ParentType, ContextType>;
longitude?: Resolver<ResolversTypes['Float'], ParentType, ContextType>;
Expand Down Expand Up @@ -4495,6 +4587,7 @@ export type MutationResolvers<ContextType = any, ParentType extends ResolversPar
callbackEndpointDelete?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationCallbackEndpointDeleteArgs, 'input'>>;
captchaCreateChallenge?: Resolver<ResolversTypes['CaptchaCreateChallengePayload'], ParentType, ContextType>;
captchaRequestAuthCode?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationCaptchaRequestAuthCodeArgs, 'input'>>;
contactCreate?: Resolver<ResolversTypes['ContactPayload'], ParentType, ContextType, RequireFields<MutationContactCreateArgs, 'input'>>;
deviceNotificationTokenCreate?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationDeviceNotificationTokenCreateArgs, 'input'>>;
feedbackSubmit?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationFeedbackSubmitArgs, 'input'>>;
intraLedgerPaymentSend?: Resolver<ResolversTypes['PaymentSendPayload'], ParentType, ContextType, RequireFields<MutationIntraLedgerPaymentSendArgs, 'input'>>;
Expand Down Expand Up @@ -4972,7 +5065,8 @@ export type UserResolvers<ContextType = any, ParentType extends ResolversParentT

export type UserContactResolvers<ContextType = any, ParentType extends ResolversParentTypes['UserContact'] = ResolversParentTypes['UserContact']> = {
alias?: Resolver<Maybe<ResolversTypes['ContactAlias']>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['Username'], ParentType, ContextType>;
handle?: Resolver<ResolversTypes['ContactHandle'], ParentType, ContextType>;
id?: Resolver<ResolversTypes['ContactHandle'], ParentType, ContextType>;
transactions?: Resolver<Maybe<ResolversTypes['TransactionConnection']>, ParentType, ContextType, Partial<UserContactTransactionsArgs>>;
transactionsCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
username?: Resolver<ResolversTypes['Username'], ParentType, ContextType>;
Expand Down Expand Up @@ -5108,7 +5202,12 @@ export type Resolvers<ContextType = any> = {
CentAmount?: GraphQLScalarType;
CentAmountPayload?: CentAmountPayloadResolvers<ContextType>;
ConsumerAccount?: ConsumerAccountResolvers<ContextType>;
Contact?: ContactResolvers<ContextType>;
ContactAlias?: GraphQLScalarType;
ContactDisplayName?: GraphQLScalarType;
ContactHandle?: GraphQLScalarType;
ContactId?: GraphQLScalarType;
ContactPayload?: ContactPayloadResolvers<ContextType>;
Coordinates?: CoordinatesResolvers<ContextType>;
Country?: CountryResolvers<ContextType>;
CountryCode?: GraphQLScalarType;
Expand Down
5 changes: 5 additions & 0 deletions apps/map/codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,8 @@ generates:
EndpointUrl: "string"
Object: "string"
NotificationCategory: "string"
AccountId: "string"
ContactId: "string"
ContactHandle: "string"
ContactType: "string"
ContactDisplayName: "string"
Loading
Loading