Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ Hi! Welcome to the contributor documentation for the `core` monorepo.
- [Building packages](./processes/building.md)
- [Adding new packages to the monorepo](./processes/adding-new-packages.md)
- [Migrating external packages to the monorepo](./processes/package-migration-process-guide.md)
- [Migrating tags](./processes/migrate-tags.md)

## Code guidelines

Expand Down
169 changes: 0 additions & 169 deletions docs/processes/migrate-tags.md

This file was deleted.

11 changes: 11 additions & 0 deletions docs/processes/package-migration-process-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ This document outlines the process for migrating a MetaMask library into the cor

- [Example PR](https://github.com/MetaMask/core/pull/1872)

#### After PR#6 lands: tag the latest source-repo release in core

`action-publish-release` checks GitHub for an existing tag before publishing. If the latest version published from the source repo has no matching tag in `core`, the action will try to release that version again and fail. Create a tag in `core` for the last source-repo release and push it to `origin`:

```shell
git tag -a @metamask/<package-name>@<latest-version> <release-commit-sha-in-core>
git push origin @metamask/<package-name>@<latest-version>
```

Find the release commit SHA with `git log --oneline merged-packages/<package-name>` and match the release commit message from the source repo.

### **[PR#7]** 2. Reset the CHANGELOG, adding a link to the old repository

- Create a fresh CHANGELOG file with no releases
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@metamask/core-monorepo",
"version": "1046.0.0",
"version": "1047.0.0",
"private": true,
"description": "Monorepo for packages shared between MetaMask clients",
"repository": {
Expand Down
5 changes: 5 additions & 0 deletions packages/authenticated-user-storage/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `getAssetsWatchlist` and `setAssetsWatchlist` methods to `AuthenticatedUserStorageService` for managing the authenticated user's assets-watchlist, along with corresponding messenger actions (`AuthenticatedUserStorageService:getAssetsWatchlist`, `AuthenticatedUserStorageService:setAssetsWatchlist`), the `AssetsWatchlistBlob` type, and the `ASSETS_WATCHLIST_MAX_ASSETS` constant ([#8836](https://github.com/MetaMask/core/pull/8836))
- `getAssetsWatchlist` returns the assets-watchlist blob or `null` on 404, mirroring `getNotificationPreferences`.
- `setAssetsWatchlist` writes the full blob and enforces a maximum of `ASSETS_WATCHLIST_MAX_ASSETS` (100) assets before sending the request, via a superstruct `size` constraint on the write-side schema.
- Add `AgenticCliPreference` type and optional `agenticCli` field to `NotificationPreferences` for Agentic CLI notification preferences ([#8933](https://github.com/MetaMask/core/pull/8933))
- `agenticCli` is optional on the type for this release; the next major release should make it required.
- `getNotificationPreferences` backfills legacy blobs that omit `agenticCli` with `DEFAULT_AGENTIC_CLI_PREFERENCES`, then validates the result against the full schema.
- `putNotificationPreferences` relies on the TypeScript type for write shape; no runtime validation is performed on PUT.
- Add `DEFAULT_AGENTIC_CLI_PREFERENCES` for Agentic CLI notification preferences ([#8933](https://github.com/MetaMask/core/pull/8933))

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ export type AuthenticatedUserStorageServiceRevokeDelegationAction = {
/**
* Returns the notification preferences for the authenticated user.
*
* Legacy payloads that omit `agenticCli` are coerced with
* {@link DEFAULT_AGENTIC_CLI_PREFERENCES} on read. When this method returns
* a non-`null` value, `agenticCli` is always present (backfilled), even
* though {@link NotificationPreferences} marks it optional until the next
* major release.
*
* @returns The notification preferences object, or `null` if none have been
* set (404).
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
MOCK_DELEGATION_RESPONSE,
MOCK_DELEGATION_SUBMISSION,
MOCK_INVALID_ASSETS_WATCHLIST_BLOB,
MOCK_LEGACY_NOTIFICATION_PREFERENCES,
MOCK_NOTIFICATION_PREFERENCES,
MOCK_ASSETS_WATCHLIST_BLOB,
MOCK_ASSETS_WATCHLIST_URL,
Expand All @@ -30,7 +31,10 @@ import {
} from './authenticated-user-storage';
import type { Environment } from './env';
import { getUserStorageApiUrl } from './env';
import { ASSETS_WATCHLIST_MAX_ASSETS } from './validators';
import {
ASSETS_WATCHLIST_MAX_ASSETS,
DEFAULT_AGENTIC_CLI_PREFERENCES,
} from './validators';

const MOCK_ACCESS_TOKEN = 'mock-access-token';

Expand Down Expand Up @@ -199,6 +203,41 @@ describe('AuthenticatedUserStorageService', () => {
'Failed to get notification preferences: 500',
);
});

it('coerces legacy payloads that omit agenticCli', async () => {
handleMockGetNotificationPreferences({
status: 200,
body: MOCK_LEGACY_NOTIFICATION_PREFERENCES,
});
const { service } = createService();

const result = await service.getNotificationPreferences();

expect(result).toStrictEqual({
...MOCK_LEGACY_NOTIFICATION_PREFERENCES,
agenticCli: DEFAULT_AGENTIC_CLI_PREFERENCES,
});
});

it('does not mutate DEFAULT_AGENTIC_CLI_PREFERENCES when coercing legacy payloads', async () => {
handleMockGetNotificationPreferences({
status: 200,
body: MOCK_LEGACY_NOTIFICATION_PREFERENCES,
});
const { service } = createService();

const result = await service.getNotificationPreferences();

expect(result).not.toBeNull();
if (!result) {
throw new Error('Result is null');
}
result.agenticCli.inAppNotificationsEnabled = false;

expect(DEFAULT_AGENTIC_CLI_PREFERENCES.inAppNotificationsEnabled).toBe(
true,
);
});
});

describe('putNotificationPreferences', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
assertAssetsWatchlistBlobForWrite,
assertDelegationResponseArray,
assertNotificationPreferences,
DEFAULT_AGENTIC_CLI_PREFERENCES,
} from './validators';

// === GENERAL ===
Expand Down Expand Up @@ -271,6 +272,12 @@ export class AuthenticatedUserStorageService extends BaseDataService<
/**
* Returns the notification preferences for the authenticated user.
*
* Legacy payloads that omit `agenticCli` are coerced with
* {@link DEFAULT_AGENTIC_CLI_PREFERENCES} on read. When this method returns
* a non-`null` value, `agenticCli` is always present (backfilled), even
* though {@link NotificationPreferences} marks it optional until the next
* major release.
*
* @returns The notification preferences object, or `null` if none have been
* set (404).
*/
Expand Down Expand Up @@ -302,8 +309,14 @@ export class AuthenticatedUserStorageService extends BaseDataService<
return null;
}

assertNotificationPreferences(data);
return data;
// backfill agenticCli preferences if it is undefined
const backfilledData = {
...data,
agenticCli: data.agenticCli ?? { ...DEFAULT_AGENTIC_CLI_PREFERENCES },
};

assertNotificationPreferences(backfilledData);
return backfilledData;
}

/**
Expand Down
6 changes: 5 additions & 1 deletion packages/authenticated-user-storage/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ export {
getAuthenticatedStorageUrl,
AuthenticatedUserStorageService,
} from './authenticated-user-storage';
export { ASSETS_WATCHLIST_MAX_ASSETS } from './validators';
export {
ASSETS_WATCHLIST_MAX_ASSETS,
DEFAULT_AGENTIC_CLI_PREFERENCES,
} from './validators';
export type {
AuthenticatedUserStorageActions,
AuthenticatedUserStorageCacheUpdatedEvent,
Expand Down Expand Up @@ -35,6 +38,7 @@ export type {
PerpsWatchlistMarkets,
PerpsPreference,
SocialAIPreference,
AgenticCliPreference,
NotificationPreferences,
AssetsWatchlistBlob,
ClientType,
Expand Down
16 changes: 15 additions & 1 deletion packages/authenticated-user-storage/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ export type WalletActivityAccount = {
enabled: boolean;
};

export type AgenticCliPreference = {
inAppNotificationsEnabled: boolean;
pushNotificationsEnabled: boolean;
};

export type WalletActivityPreference = {
inAppNotificationsEnabled: boolean;
pushNotificationsEnabled: boolean;
Expand Down Expand Up @@ -103,12 +108,21 @@ export type SocialAIPreference = {
mutedTraderProfileIds: string[];
};

/** Notification preferences for the authenticated user. */
/**
* Notification preferences for the authenticated user.
*
* `agenticCli` is optional on this type for the current minor release.
* {@link AuthenticatedUserStorageService.getNotificationPreferences} always
* backfills it when absent from stored data. The next major release should
* make `agenticCli` required on this type.
*/
export type NotificationPreferences = {
walletActivity: WalletActivityPreference;
marketing: MarketingPreference;
perps: PerpsPreference;
socialAI: SocialAIPreference;
/** Optional until the next major release; always backfilled on read when absent. */
agenticCli?: AgenticCliPreference;
};

// ---------------------------------------------------------------------------
Expand Down
Loading
Loading