gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated (610df1c9c -> ded00b680)


From: gnunet
Subject: [taler-wallet-core] branch master updated (610df1c9c -> ded00b680)
Date: Wed, 12 Oct 2022 22:27:53 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch master
in repository wallet-core.

    from 610df1c9c create a fee description timeline for global fee and wire 
fees
     new 8bfa77200 wallet-core: handle missing purchase status cases
     new 3da1e82a2 wallet-core: skeleton for dev-experiments
     new ded00b680 wallet-core: implement enabling/disabling dev mode

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .vscode/settings.json                              |   1 -
 packages/taler-util/src/taleruri.ts                |  21 +++
 packages/taler-util/src/walletTypes.ts             |  11 ++
 packages/taler-wallet-cli/src/index.ts             |   8 ++
 packages/taler-wallet-core/src/db.ts               |  49 ++++---
 packages/taler-wallet-core/src/dev-experiments.ts  | 154 +++++++++++++++++++++
 .../taler-wallet-core/src/internal-wallet-state.ts |   2 +
 .../src/operations/backup/export.ts                |   4 +-
 .../src/operations/backup/index.ts                 |   8 +-
 .../src/operations/backup/state.ts                 |  20 +--
 .../src/operations/pay-merchant.ts                 |   6 +-
 packages/taler-wallet-core/src/util/http.ts        |   4 +
 packages/taler-wallet-core/src/wallet-api-types.ts |  17 ++-
 packages/taler-wallet-core/src/wallet.ts           |  14 +-
 14 files changed, 279 insertions(+), 40 deletions(-)
 create mode 100644 packages/taler-wallet-core/src/dev-experiments.ts

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 97596d26c..803c58a07 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -21,7 +21,6 @@
   // Defines whether an open brace is put onto a new line for control blocks 
or not
   "typescript.format.placeOpenBraceOnNewLineForControlBlocks": false,
   "typescript.preferences.autoImportFileExcludePatterns": [
-    "index.js",
     "index.*.js",
     "index.ts",
     "index.*.ts"
diff --git a/packages/taler-util/src/taleruri.ts 
b/packages/taler-util/src/taleruri.ts
index e7d66d7d5..baca3efac 100644
--- a/packages/taler-util/src/taleruri.ts
+++ b/packages/taler-util/src/taleruri.ts
@@ -50,6 +50,10 @@ export interface PayPullUriResult {
   contractPriv: string;
 }
 
+export interface DevExperimentUri {
+  devExperimentId: string;
+}
+
 /**
  * Parse a taler[+http]://withdraw URI.
  * Return undefined if not passed a valid URI.
@@ -91,6 +95,7 @@ export enum TalerUriType {
   TalerNotifyReserve = "taler-notify-reserve",
   TalerPayPush = "taler-pay-push",
   TalerPayPull = "taler-pay-pull",
+  TalerDevExperiment = "taler-dev-experiment",
   Unknown = "unknown",
 }
 
@@ -141,6 +146,9 @@ export function classifyTalerUri(s: string): TalerUriType {
   if (sl.startsWith("taler://notify-reserve/")) {
     return TalerUriType.TalerNotifyReserve;
   }
+  if (sl.startsWith("taler://dev-experiment/")) {
+    return TalerUriType.TalerDevExperiment;
+  }
   return TalerUriType.Unknown;
 }
 
@@ -300,6 +308,19 @@ export function parseRefundUri(s: string): RefundUriResult 
| undefined {
   };
 }
 
+export function parseDevExperimentUri(s: string): DevExperimentUri | undefined 
{
+  const pi = parseProtoInfo(s, "dev-experiment");
+  const c = pi?.rest.split("?");
+  if (!c) {
+    return undefined;
+  }
+  // const q = new URLSearchParams(c[1] ?? "");
+  const parts = c[0].split("/");
+  return {
+    devExperimentId: parts[0],
+  };
+}
+
 export function constructPayPushUri(args: {
   exchangeBaseUrl: string;
   contractPriv: string;
diff --git a/packages/taler-util/src/walletTypes.ts 
b/packages/taler-util/src/walletTypes.ts
index 7495e02d6..a1fa9b439 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -605,6 +605,7 @@ export interface WalletCoreVersion {
   exchange: string;
   merchant: string;
   bank: string;
+  devMode?: boolean;
 }
 
 export interface KnownBankAccountsInfo {
@@ -1683,6 +1684,16 @@ export interface AcceptPeerPullPaymentRequest {
   peerPullPaymentIncomingId: string;
 }
 
+export interface ApplyDevExperimentRequest {
+  devExperimentUri: string;
+}
+
+export const codecForApplyDevExperiment =
+  (): Codec<ApplyDevExperimentRequest> =>
+    buildCodecForObject<ApplyDevExperimentRequest>()
+      .property("devExperimentUri", codecForString())
+      .build("ApplyDevExperimentRequest");
+
 export const codecForAcceptPeerPullPaymentRequest =
   (): Codec<AcceptPeerPullPaymentRequest> =>
     buildCodecForObject<AcceptPeerPullPaymentRequest>()
diff --git a/packages/taler-wallet-cli/src/index.ts 
b/packages/taler-wallet-cli/src/index.ts
index 7ff369a5e..09ab414ac 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -43,6 +43,7 @@ import {
   setDangerousTimetravel,
   setGlobalLogLevelFromString,
   TalerUriType,
+  parseDevExperimentUri,
 } from "@gnu-taler/taler-util";
 import {
   CryptoDispatcher,
@@ -67,6 +68,7 @@ import { runEnv1 } from "./env1.js";
 import { GlobalTestState, runTestWithState } from "./harness/harness.js";
 import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
 import { lintExchangeDeployment } from "./lint.js";
+import { checkLogicInvariant } from 
"@gnu-taler/taler-wallet-core/src/util/invariants.js";
 // @ts-ignore
 global.TextEncoder = TextEncoder;
 // @ts-ignore
@@ -498,6 +500,12 @@ walletCli
             console.log("accept withdrawal response", res);
           }
           break;
+        case TalerUriType.TalerDevExperiment: {
+          await wallet.client.call(WalletApiOperation.ApplyDevExperiment, {
+            devExperimentUri: uri,
+          });
+          break;
+        }
         default:
           console.log(`URI type (${uriType}) not handled`);
           break;
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 125e777b8..f4cdb68c1 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -103,6 +103,8 @@ export const WALLET_DB_MINOR_VERSION = 2;
 export enum OperationStatusRange {
   ACTIVE_START = 10,
   ACTIVE_END = 29,
+  USER_ATTENTION_START = 30,
+  USER_ATTENTION_END = 49,
   DORMANT_START = 50,
   DORMANT_END = 69,
 }
@@ -114,36 +116,36 @@ export enum WithdrawalGroupStatus {
   /**
    * Reserve must be registered with the bank.
    */
-  RegisteringBank = OperationStatusRange.ACTIVE_START,
+  RegisteringBank = 10,
 
   /**
    * We've registered reserve's information with the bank
    * and are now waiting for the user to confirm the withdraw
    * with the bank (typically 2nd factor auth).
    */
-  WaitConfirmBank = OperationStatusRange.ACTIVE_START + 1,
+  WaitConfirmBank = 11,
 
   /**
    * Querying reserve status with the exchange.
    */
-  QueryingStatus = OperationStatusRange.ACTIVE_START + 2,
+  QueryingStatus = 12,
 
   /**
    * Ready for withdrawal.
    */
-  Ready = OperationStatusRange.ACTIVE_START + 3,
+  Ready = 13,
 
   /**
    * The corresponding withdraw record has been created.
    * No further processing is done, unless explicitly requested
    * by the user.
    */
-  Finished = OperationStatusRange.DORMANT_START,
+  Finished = 50,
 
   /**
    * The bank aborted the withdrawal.
    */
-  BankAborted = OperationStatusRange.DORMANT_START + 1,
+  BankAborted = 51,
 }
 
 /**
@@ -1036,59 +1038,59 @@ export enum PurchaseStatus {
   /**
    * Not downloaded yet.
    */
-  DownloadingProposal = OperationStatusRange.ACTIVE_START,
+  DownloadingProposal = 10,
 
   /**
    * The user has accepted the proposal.
    */
-  Paying = OperationStatusRange.ACTIVE_START + 1,
+  Paying = 11,
 
-  AbortingWithRefund = OperationStatusRange.ACTIVE_START + 2,
+  AbortingWithRefund = 12,
 
   /**
    * Paying a second time, likely with different session ID
    */
-  PayingReplay = OperationStatusRange.ACTIVE_START + 3,
+  PayingReplay = 13,
 
   /**
    * Query for refunds (until query succeeds).
    */
-  QueryingRefund = OperationStatusRange.ACTIVE_START + 4,
+  QueryingRefund = 14,
 
   /**
    * Query for refund (until auto-refund deadline is reached).
    */
-  QueryingAutoRefund = OperationStatusRange.ACTIVE_START + 5,
+  QueryingAutoRefund = 15,
 
   /**
    * Proposal downloaded, but the user needs to accept/reject it.
    */
-  Proposed = OperationStatusRange.DORMANT_START,
+  Proposed = 30,
 
   /**
    * The user has rejected the proposal.
    */
-  ProposalRefused = OperationStatusRange.DORMANT_START + 1,
+  ProposalRefused = 50,
 
   /**
    * Downloading or processing the proposal has failed permanently.
    */
-  ProposalDownloadFailed = OperationStatusRange.DORMANT_START + 2,
+  ProposalDownloadFailed = 51,
 
   /**
    * Downloaded proposal was detected as a re-purchase.
    */
-  RepurchaseDetected = OperationStatusRange.DORMANT_START + 3,
+  RepurchaseDetected = 52,
 
   /**
    * The payment has been aborted.
    */
-  PaymentAbortFinished = OperationStatusRange.DORMANT_START + 4,
+  PaymentAbortFinished = 53,
 
   /**
    * Payment was successful.
    */
-  Paid = OperationStatusRange.DORMANT_START + 5,
+  Paid = 54,
 }
 
 /**
@@ -1238,7 +1240,11 @@ export interface PurchaseRecord {
   refundAmountAwaiting: AmountJson | undefined;
 }
 
-export const WALLET_BACKUP_STATE_KEY = "walletBackupState";
+export enum ConfigRecordKey {
+  WalletBackupState = "walletBackupState",
+  CurrencyDefaultsApplied = "currencyDefaultsApplied",
+  DevMode = "devMode",
+}
 
 /**
  * Configuration key/value entries to configure
@@ -1246,10 +1252,11 @@ export const WALLET_BACKUP_STATE_KEY = 
"walletBackupState";
  */
 export type ConfigRecord =
   | {
-      key: typeof WALLET_BACKUP_STATE_KEY;
+      key: ConfigRecordKey.WalletBackupState;
       value: WalletBackupConfState;
     }
-  | { key: "currencyDefaultsApplied"; value: boolean };
+  | { key: ConfigRecordKey.CurrencyDefaultsApplied; value: boolean }
+  | { key: ConfigRecordKey.DevMode; value: boolean };
 
 export interface WalletBackupConfState {
   deviceId: string;
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts 
b/packages/taler-wallet-core/src/dev-experiments.ts
new file mode 100644
index 000000000..c3167b3e4
--- /dev/null
+++ b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -0,0 +1,154 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Implementation of dev experiments, i.e. scenarios
+ * triggered by taler://dev-experiment URIs.
+ *
+ * @author Florian Dold <dold@taler.net>
+ */
+
+/**
+ * Imports.
+ */
+
+import { Logger, parseDevExperimentUri } from "@gnu-taler/taler-util";
+import { ConfigRecordKey } from "./db.js";
+import { InternalWalletState } from "./internal-wallet-state.js";
+import {
+  HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
+} from "./util/http.js";
+
+const logger = new Logger("dev-experiments.ts");
+
+/**
+ * Apply a dev experiment to the wallet database / state.
+ */
+export async function applyDevExperiment(
+  ws: InternalWalletState,
+  uri: string,
+): Promise<void> {
+  logger.info(`applying dev experiment ${uri}`);
+  const parsedUri = parseDevExperimentUri(uri);
+  if (!parsedUri) {
+    logger.info("unable to parse dev experiment URI");
+    return;
+  }
+  if (parsedUri.devExperimentId == "enable-devmode") {
+    logger.info("enabling devmode");
+    await ws.db
+      .mktx((x) => [x.config])
+      .runReadWrite(async (tx) => {
+        tx.config.put({
+          key: ConfigRecordKey.DevMode,
+          value: true,
+        });
+      });
+    await maybeInitDevMode(ws);
+    return;
+  }
+  if (parsedUri.devExperimentId === "disable-devmode") {
+    logger.info("disabling devmode");
+    await ws.db
+      .mktx((x) => [x.config])
+      .runReadWrite(async (tx) => {
+        tx.config.put({
+          key: ConfigRecordKey.DevMode,
+          value: false,
+        });
+      });
+    await leaveDevMode(ws);
+    return;
+  }
+  if (!ws.devModeActive) {
+    throw Error(
+      "can't handle devmode URI (other than enable-devmode) unless devmode is 
active",
+    );
+  }
+  throw Error(`dev-experiment id not understood ${parsedUri.devExperimentId}`);
+}
+
+/**
+ * Enter dev mode, if the wallet's config entry in the DB demands it.
+ */
+export async function maybeInitDevMode(ws: InternalWalletState): Promise<void> 
{
+  const devMode = await ws.db
+    .mktx((x) => [x.config])
+    .runReadOnly(async (tx) => {
+      const rec = await tx.config.get(ConfigRecordKey.DevMode);
+      if (!rec || rec.key !== ConfigRecordKey.DevMode) {
+        return false;
+      }
+      return rec.value;
+    });
+  if (!devMode) {
+    ws.devModeActive = false;
+    return;
+  }
+  ws.devModeActive = true;
+  if (ws.http instanceof DevExperimentHttpLib) {
+    return;
+  }
+  ws.http = new DevExperimentHttpLib(ws.http);
+}
+
+export async function leaveDevMode(ws: InternalWalletState): Promise<void> {
+  if (ws.http instanceof DevExperimentHttpLib) {
+    ws.http = ws.http.underlyingLib;
+  }
+  ws.devModeActive = false;
+}
+
+export class DevExperimentHttpLib implements HttpRequestLibrary {
+  _isDevExperimentLib = true;
+  underlyingLib: HttpRequestLibrary;
+
+  constructor(lib: HttpRequestLibrary) {
+    this.underlyingLib = lib;
+  }
+
+  get(
+    url: string,
+    opt?: HttpRequestOptions | undefined,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "GET",
+      ...opt,
+    });
+  }
+
+  postJson(
+    url: string,
+    body: any,
+    opt?: HttpRequestOptions | undefined,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "POST",
+      body,
+      ...opt,
+    });
+  }
+
+  fetch(
+    url: string,
+    opt?: HttpRequestOptions | undefined,
+  ): Promise<HttpResponse> {
+    logger.info(`devexperiment httplib ${url}`);
+    return this.underlyingLib.fetch(url, opt);
+  }
+}
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts 
b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 6c7d943cb..bc956bd17 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -191,6 +191,8 @@ export interface InternalWalletState {
   merchantOps: MerchantOperations;
   refreshOps: RefreshOperations;
 
+  devModeActive: boolean;
+
   getDenomInfo(
     ws: InternalWalletState,
     tx: GetReadOnlyAccess<{
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts 
b/packages/taler-wallet-core/src/operations/backup/export.ts
index a3c4c8d99..c7890b5d8 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -64,11 +64,11 @@ import {
 import {
   CoinSourceType,
   CoinStatus,
+  ConfigRecordKey,
   DenominationRecord,
   PurchaseStatus,
   RefreshCoinStatus,
   RefundState,
-  WALLET_BACKUP_STATE_KEY,
   WithdrawalGroupStatus,
   WithdrawalRecordType,
 } from "../../db.js";
@@ -547,7 +547,7 @@ export async function exportBackup(
           )} and nonce to ${bs.lastBackupNonce}`,
         );
         await tx.config.put({
-          key: WALLET_BACKUP_STATE_KEY,
+          key: ConfigRecordKey.WalletBackupState,
           value: bs,
         });
       } else {
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts 
b/packages/taler-wallet-core/src/operations/backup/index.ts
index 3d3ebf04a..8e5e69097 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -74,8 +74,8 @@ import {
   BackupProviderStateTag,
   BackupProviderTerms,
   ConfigRecord,
+  ConfigRecordKey,
   WalletBackupConfState,
-  WALLET_BACKUP_STATE_KEY,
 } from "../../db.js";
 import { InternalWalletState } from "../../internal-wallet-state.js";
 import {
@@ -861,10 +861,12 @@ async function backupRecoveryTheirs(
     .mktx((x) => [x.config, x.backupProviders])
     .runReadWrite(async (tx) => {
       let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
-        WALLET_BACKUP_STATE_KEY,
+        ConfigRecordKey.WalletBackupState,
       );
       checkDbInvariant(!!backupStateEntry);
-      checkDbInvariant(backupStateEntry.key === WALLET_BACKUP_STATE_KEY);
+      checkDbInvariant(
+        backupStateEntry.key === ConfigRecordKey.WalletBackupState,
+      );
       backupStateEntry.value.lastBackupNonce = undefined;
       backupStateEntry.value.lastBackupTimestamp = undefined;
       backupStateEntry.value.lastBackupCheckTimestamp = undefined;
diff --git a/packages/taler-wallet-core/src/operations/backup/state.ts 
b/packages/taler-wallet-core/src/operations/backup/state.ts
index 2efd9be8e..b8dbb15c1 100644
--- a/packages/taler-wallet-core/src/operations/backup/state.ts
+++ b/packages/taler-wallet-core/src/operations/backup/state.ts
@@ -17,9 +17,9 @@
 import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
 import {
   ConfigRecord,
+  ConfigRecordKey,
   WalletBackupConfState,
   WalletStoresV1,
-  WALLET_BACKUP_STATE_KEY,
 } from "../../db.js";
 import { checkDbInvariant } from "../../util/invariants.js";
 import { GetReadOnlyAccess } from "../../util/query.js";
@@ -31,10 +31,10 @@ export async function provideBackupState(
   const bs: ConfigRecord | undefined = await ws.db
     .mktx((stores) => [stores.config])
     .runReadOnly(async (tx) => {
-      return await tx.config.get(WALLET_BACKUP_STATE_KEY);
+      return await tx.config.get(ConfigRecordKey.WalletBackupState);
     });
   if (bs) {
-    checkDbInvariant(bs.key === WALLET_BACKUP_STATE_KEY);
+    checkDbInvariant(bs.key === ConfigRecordKey.WalletBackupState);
     return bs.value;
   }
   // We need to generate the key outside of the transaction
@@ -48,11 +48,11 @@ export async function provideBackupState(
     .mktx((x) => [x.config])
     .runReadWrite(async (tx) => {
       let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
-        WALLET_BACKUP_STATE_KEY,
+        ConfigRecordKey.WalletBackupState,
       );
       if (!backupStateEntry) {
         backupStateEntry = {
-          key: WALLET_BACKUP_STATE_KEY,
+          key: ConfigRecordKey.WalletBackupState,
           value: {
             deviceId,
             walletRootPub: k.pub,
@@ -62,7 +62,7 @@ export async function provideBackupState(
         };
         await tx.config.put(backupStateEntry);
       }
-      checkDbInvariant(backupStateEntry.key === WALLET_BACKUP_STATE_KEY);
+      checkDbInvariant(backupStateEntry.key === 
ConfigRecordKey.WalletBackupState);
       return backupStateEntry.value;
     });
 }
@@ -71,9 +71,9 @@ export async function getWalletBackupState(
   ws: InternalWalletState,
   tx: GetReadOnlyAccess<{ config: typeof WalletStoresV1.config }>,
 ): Promise<WalletBackupConfState> {
-  const bs = await tx.config.get(WALLET_BACKUP_STATE_KEY);
+  const bs = await tx.config.get(ConfigRecordKey.WalletBackupState);
   checkDbInvariant(!!bs, "wallet backup state should be in DB");
-  checkDbInvariant(bs.key === WALLET_BACKUP_STATE_KEY);
+  checkDbInvariant(bs.key === ConfigRecordKey.WalletBackupState);
   return bs.value;
 }
 
@@ -86,11 +86,11 @@ export async function setWalletDeviceId(
     .mktx((x) => [x.config])
     .runReadWrite(async (tx) => {
       let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
-        WALLET_BACKUP_STATE_KEY,
+        ConfigRecordKey.WalletBackupState,
       );
       if (
         !backupStateEntry ||
-        backupStateEntry.key !== WALLET_BACKUP_STATE_KEY
+        backupStateEntry.key !== ConfigRecordKey.WalletBackupState
       ) {
         return;
       }
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts 
b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 750b3b9a6..d45a93056 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -1797,12 +1797,16 @@ export async function processPurchase(
     case PurchaseStatus.ProposalDownloadFailed:
     case PurchaseStatus.Paid:
     case PurchaseStatus.RepurchaseDetected:
+    case PurchaseStatus.Proposed:
+    case PurchaseStatus.ProposalRefused:
+    case PurchaseStatus.PaymentAbortFinished:
       return {
         type: OperationAttemptResultType.Finished,
         result: undefined,
       };
     default:
-      throw Error(`unexpected purchase status (${purchase.purchaseStatus})`);
+      assertUnreachable(purchase.purchaseStatus);
+    // throw Error(`unexpected purchase status (${purchase.purchaseStatus})`);
   }
 }
 
diff --git a/packages/taler-wallet-core/src/util/http.ts 
b/packages/taler-wallet-core/src/util/http.ts
index 58edd289b..0489f920b 100644
--- a/packages/taler-wallet-core/src/util/http.ts
+++ b/packages/taler-wallet-core/src/util/http.ts
@@ -111,11 +111,15 @@ export class Headers {
 export interface HttpRequestLibrary {
   /**
    * Make an HTTP GET request.
+   *
+   * FIXME: Get rid of this, we want the API surface to be minimal.
    */
   get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
 
   /**
    * Make an HTTP POST request with a JSON body.
+   *
+   * FIXME: Get rid of this, we want the API surface to be minimal.
    */
   postJson(
     url: string,
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts 
b/packages/taler-wallet-core/src/wallet-api-types.ts
index 15de5faf9..cecdd1281 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -80,6 +80,7 @@ import {
   WithdrawTestBalanceRequest,
   WithdrawUriInfoResponse,
 } from "@gnu-taler/taler-util";
+import { ApplyDevExperimentRequest } from "@gnu-taler/taler-util";
 import {
   AddBackupProviderRequest,
   BackupInfo,
@@ -139,6 +140,7 @@ export enum WalletApiOperation {
   AcceptPeerPullPayment = "acceptPeerPullPayment",
   ClearDb = "clearDb",
   Recycle = "recycle",
+  ApplyDevExperiment = "applyDevExperiment",
 }
 
 // group: Initialization
@@ -487,7 +489,7 @@ export type AcceptPeerPullPaymentOp = {
 // group: Database Management
 
 /**
- * Exoport the wallet database's contents to JSON.
+ * Export the wallet database's contents to JSON.
  */
 export type ExportDbOp = {
   op: WalletApiOperation.ExportDb;
@@ -515,6 +517,18 @@ export type RecycleOp = {
 
 // group: Testing and Debugging
 
+/**
+ * Apply a developer experiment to the current wallet state.
+ *
+ * This allows UI developers / testers to play around without
+ * an elaborate test environment.
+ */
+export type ApplyDevExperimentOp = {
+  op: WalletApiOperation.ApplyDevExperiment;
+  request: ApplyDevExperimentRequest;
+  response: {};
+};
+
 /**
  * Run a simple integration test on a test deployment
  * of the exchange and merchant.
@@ -661,6 +675,7 @@ export type WalletOperations = {
   [WalletApiOperation.AcceptPeerPullPayment]: AcceptPeerPullPaymentOp;
   [WalletApiOperation.ClearDb]: ClearDbOp;
   [WalletApiOperation.Recycle]: RecycleOp;
+  [WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp;
 };
 
 export type RequestType<
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index 357dd586a..48d379931 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -90,6 +90,7 @@ import {
   parsePaytoUri,
   RefreshReason,
   TalerErrorCode,
+  codecForApplyDevExperiment,
   URL,
   WalletCoreVersion,
   WalletNotification,
@@ -104,11 +105,13 @@ import {
   AuditorTrustRecord,
   CoinSourceType,
   CoinStatus,
+  ConfigRecordKey,
   DenominationRecord,
   exportDb,
   importDb,
   WalletStoresV1,
 } from "./db.js";
+import { applyDevExperiment, maybeInitDevMode } from "./dev-experiments.js";
 import { getErrorDetailFromException, TalerError } from "./errors.js";
 import {
   ActiveLongpollInfo,
@@ -474,7 +477,7 @@ async function fillDefaults(ws: InternalWalletState): 
Promise<void> {
         provideExchangeRecordInTx(ws, tx, baseUrl, now);
       }
       await tx.config.put({
-        key: "currencyDefaultsApplied",
+        key: ConfigRecordKey.CurrencyDefaultsApplied,
         value: true,
       });
     });
@@ -968,6 +971,7 @@ async function dispatchRequestInternal(
         logger.trace("filling defaults");
         await fillDefaults(ws);
       }
+      await maybeInitDevMode(ws);
       return {};
     }
     case "withdrawTestkudos": {
@@ -1325,6 +1329,11 @@ async function dispatchRequestInternal(
       const req = codecForAcceptPeerPullPaymentRequest().decode(payload);
       return await acceptPeerPullPayment(ws, req);
     }
+    case "applyDevExperiment": {
+      const req = codecForApplyDevExperiment().decode(payload);
+      await applyDevExperiment(ws, req.devExperimentUri);
+      return {};
+    }
     case "getVersion": {
       const version: WalletCoreVersion = {
         hash: GIT_HASH,
@@ -1332,6 +1341,7 @@ async function dispatchRequestInternal(
         exchange: WALLET_EXCHANGE_PROTOCOL_VERSION,
         merchant: WALLET_MERCHANT_PROTOCOL_VERSION,
         bank: WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
+        devMode: ws.devModeActive,
       };
       return version;
     }
@@ -1473,6 +1483,8 @@ class InternalWalletStateImpl implements 
InternalWalletState {
 
   initCalled = false;
 
+  devModeActive = false;
+
   exchangeOps: ExchangeOperations = {
     getExchangeDetails,
     getExchangeTrust,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]