UNPKG

@daml/react

Version:

React framework to interact with a Daml ledger

351 lines • 17.3 kB
"use strict"; // Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createLedgerContext = createLedgerContext; var react_1 = __importStar(require("react")); var ledger_1 = __importDefault(require("@daml/ledger")); /** * Create a [[LedgerContext]]. One should use this function, instead of the default [[DamlLedger]], * where one needs to be able to nest ledger interactions, by different parties or connections, within * one React application. * * @param contextName Used to refer to a context in case of errors. */ function createLedgerContext(contextName) { // NOTE(MH, useEffect dependencies): There are various places in this file // where we need to maintain the dependencies of the `useEffect` hook manually // and there's no tool to help us enfore they are correct. Thus, we need to be // extra careful in these locations. If we add too many dependencies, we will // make unnecessary network requests. If we forget adding some dependencies, we // not make a new network request although they are required to refresh data. if (contextName === void 0) { contextName = "DamlLedgerContext"; } var ledgerContext = react_1.default.createContext(undefined); var DamlLedger = function (_a) { var token = _a.token, httpBaseUrl = _a.httpBaseUrl, wsBaseUrl = _a.wsBaseUrl, reconnectThreshold = _a.reconnectThreshold, user = _a.user, party = _a.party, children = _a.children; var _b = (0, react_1.useState)(0), reloadToken = _b[0], setReloadToken = _b[1]; var ledger = (0, react_1.useMemo)(function () { return new ledger_1.default({ token: token, httpBaseUrl: httpBaseUrl, wsBaseUrl: wsBaseUrl, reconnectThreshold: reconnectThreshold }); }, [token, httpBaseUrl, wsBaseUrl, reconnectThreshold]); var state = (0, react_1.useMemo)(function () { return ({ reloadToken: reloadToken, triggerReload: function () { return setReloadToken(function (x) { return x + 1; }); }, user: user, party: party, ledger: ledger, }); }, [party, ledger, reloadToken]); return react_1.default.createElement(ledgerContext.Provider, { value: state }, children); }; var useDamlState = function () { var state = (0, react_1.useContext)(ledgerContext); if (!state) { throw Error("Trying to use ".concat(contextName, " before initializing.")); } return state; }; var useParty = function () { var state = useDamlState(); return state.party; }; var useLedger = function () { return useDamlState().ledger; }; var useUser = function () { var user = useDamlState().user; if (!user) { throw Error("Trying to use 'useUser' for a DamlLedger with a missing 'user' field."); } else return user; }; function useQuery(template, queryFactory, queryDeps) { var _this = this; var state = useDamlState(); var _a = (0, react_1.useState)({ contracts: [], loading: true, }), result = _a[0], setResult = _a[1]; (0, react_1.useEffect)(function () { setResult({ contracts: [], loading: true }); var query = queryFactory ? queryFactory() : undefined; var load = function () { return __awaiter(_this, void 0, void 0, function () { var contracts; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, state.ledger.query(template, query)]; case 1: contracts = _a.sent(); setResult({ contracts: contracts, loading: false }); return [2 /*return*/]; } }); }); }; // eslint-disable-next-line @typescript-eslint/no-floating-promises load(); // NOTE(MH): See note at the top of the file regarding "useEffect dependencies". }, __spreadArray([state.ledger, state.reloadToken, template], (queryDeps !== null && queryDeps !== void 0 ? queryDeps : []), true)); return result; } function useFetch(template, contractId) { var _this = this; var state = useDamlState(); var _a = (0, react_1.useState)({ contract: null, loading: true, }), result = _a[0], setResult = _a[1]; (0, react_1.useEffect)(function () { setResult({ contract: null, loading: true }); var load = function () { return __awaiter(_this, void 0, void 0, function () { var contract; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, state.ledger.fetch(template, contractId)]; case 1: contract = _a.sent(); setResult({ contract: contract, loading: false }); return [2 /*return*/]; } }); }); }; // eslint-disable-next-line @typescript-eslint/no-floating-promises load(); // NOTE(MH): See note at the top of the file regarding "useEffect dependencies". }, [state.ledger, state.reloadToken, template, contractId]); return result; } function useFetchByKey(template, keyFactory, keyDeps) { var _this = this; var state = useDamlState(); var _a = (0, react_1.useState)({ contract: null, loading: true, }), result = _a[0], setResult = _a[1]; (0, react_1.useEffect)(function () { var key = keyFactory(); setResult({ contract: null, loading: true }); var load = function () { return __awaiter(_this, void 0, void 0, function () { var contract; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, state.ledger.fetchByKey(template, key)]; case 1: contract = _a.sent(); setResult({ contract: contract, loading: false }); return [2 /*return*/]; } }); }); }; // eslint-disable-next-line @typescript-eslint/no-floating-promises load(); // NOTE(MH): See note at the top of the file regarding "useEffect dependencies". }, __spreadArray([state.ledger, state.reloadToken, template], (keyDeps !== null && keyDeps !== void 0 ? keyDeps : []), true)); return result; } function useStream(_a) { var name = _a.name, template = _a.template, init = _a.init, mkStream = _a.mkStream, setLoading = _a.setLoading, setData = _a.setData, deps = _a.deps, closeHandler = _a.closeHandler; var _b = (0, react_1.useState)(init), result = _b[0], setResult = _b[1]; var state = useDamlState(); (0, react_1.useEffect)(function () { setResult(init); var _a = mkStream(state), stream = _a[0], debugQuery = _a[1]; console.debug("mount ".concat(name, "(").concat(template.templateId, ", ...)"), debugQuery); stream.on("live", function () { return setResult(function (result) { return setLoading(result, false); }); }); stream.on("change", function (contracts) { return setResult(function (result) { return setData(result, contracts); }); }); if (closeHandler) { stream.on("close", closeHandler); } else { stream.on("close", function (closeEvent) { if (closeEvent.code === 4000) { // deliberate call to .close, nothing to do } else { console.error("".concat(name, ": WebSocket connection failed.")); setResult(function (result) { return setLoading(result, true); }); } }); } return function () { console.debug("unmount ".concat(name, "(").concat(template.templateId, ", ...)"), debugQuery); stream.close(); }; // NOTE(MH): See note at the top of the file regarding "useEffect dependencies". }, __spreadArray([state.ledger, template], deps, true)); return result; } function useStreamQuery(template, queryFactory, queryDeps, closeHandler) { return useStream({ name: "useStreamQuery", template: template, init: { loading: true, contracts: [] }, mkStream: function (state) { var query = queryFactory ? [queryFactory()] : []; var stream = state.ledger.streamQueries(template, query); return [stream, query]; }, setLoading: function (r, b) { return (__assign(__assign({}, r), { loading: b })); }, setData: function (r, d) { return (__assign(__assign({}, r), { contracts: d })); }, deps: queryDeps !== null && queryDeps !== void 0 ? queryDeps : [], closeHandler: closeHandler, }); } function useStreamQueries(template, queryFactory, queryDeps, closeHandler) { return useStream({ name: "useStreamQueries", template: template, init: { loading: true, contracts: [] }, mkStream: function (state) { var query = queryFactory ? queryFactory() : []; var stream = state.ledger.streamQueries(template, query); return [stream, query]; }, setLoading: function (r, b) { return (__assign(__assign({}, r), { loading: b })); }, setData: function (r, d) { return (__assign(__assign({}, r), { contracts: d })); }, deps: queryDeps !== null && queryDeps !== void 0 ? queryDeps : [], closeHandler: closeHandler, }); } function useStreamFetchByKey(template, keyFactory, keyDeps, closeHandler) { return useStream({ name: "useStreamFetchByKey", template: template, init: { loading: true, contract: null }, mkStream: function (state) { var key = keyFactory(); var stream = state.ledger.streamFetchByKeys(template, [key]); return [stream, key]; }, setLoading: function (r, b) { return (__assign(__assign({}, r), { loading: b })); }, setData: function (r, d) { return (__assign(__assign({}, r), { contract: d[0] })); }, deps: keyDeps, closeHandler: closeHandler, }); } function useStreamFetchByKeys(template, keyFactory, keyDeps, closeHandler) { return useStream({ name: "useStreamFetchByKeys", template: template, init: { loading: true, contracts: [] }, mkStream: function (state) { var keys = keyFactory(); var stream = state.ledger.streamFetchByKeys(template, keys); return [stream, keys]; }, setLoading: function (r, b) { return (__assign(__assign({}, r), { loading: b })); }, setData: function (r, d) { return (__assign(__assign({}, r), { contracts: d })); }, deps: keyDeps, closeHandler: closeHandler, }); } var useReload = function () { var state = useDamlState(); return function () { return state.triggerReload(); }; }; return { DamlLedger: DamlLedger, useParty: useParty, useUser: useUser, useLedger: useLedger, useQuery: useQuery, useFetch: useFetch, useFetchByKey: useFetchByKey, useStreamQuery: useStreamQuery, useStreamQueries: useStreamQueries, useStreamFetchByKey: useStreamFetchByKey, useStreamFetchByKeys: useStreamFetchByKeys, useReload: useReload, }; } //# sourceMappingURL=createLedgerContext.js.map