@daml/react
Version:
React framework to interact with a Daml ledger
351 lines • 17.3 kB
JavaScript
;
// 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