From 0def6ee3ef7fbeac859e226088d7efd2dca04d52 Mon Sep 17 00:00:00 2001 From: bbface <152608874+bb-face@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:16:38 +0100 Subject: [PATCH 1/5] 127 customize gateway from bosconfigjson (#147) * Allow 'gateway' option in bos.config.json schema * Implement gateway precedence logic * Add gateway object * Fix gateway object * Fix bug * Enforce tagName and bundleUrl rules * Fix test * Gateway object for multi app * Tackle pr comments * Address pr comments * Restore gatewayInitPromise * Fix logs * Remove -g option from the cli * Remove notes * Add test to verify tagName * Remove redundant fallback --------- Co-authored-by: Elliot Braem <16282460+elliotBraem@users.noreply.github.com> --- README.md | 18 +++++++---- examples/single/bos.config.json | 6 +++- lib/cli.ts | 2 -- lib/config.ts | 6 ++++ lib/dev.ts | 42 +++++++++++++++++++++++-- lib/gateway.ts | 6 ++-- lib/server.ts | 56 ++++++++++++++++----------------- tests/unit/dev.ts | 8 +++-- tests/unit/gateway.ts | 24 ++++++++++---- tests/unit/server.ts | 28 ++++++++++------- 10 files changed, 131 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index e64db19..61037da 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,10 @@ A fully featured config may look like this: "uploadApi": "https://ipfs.near.social/add", "uploadApiHeaders": {}, }, + "gateway": { + "bundleUrl": "https://ipfs.web4.near.page/ipfs/bafybeibe63hqugbqr4writdxgezgl5swgujay6t5uptw2px7q63r7crk2q/", + "tagName": "near-social-viewer" + } } ``` @@ -131,6 +135,9 @@ The `bos.config.json` file consists of a base configuration that defines default * `format`: (Optional) Indicates whether to format code on build. Default value is `true`. * `aliases`: (Optional) Provides a list of alias files to use for replacing network-specific values with correct overrides. * `index`: (Optional) Default widget src to use when using a custom gateway dist. +* `gateway`: (Optional) Configures gateway object. + * `bundleUrl`: gateway url. + * `tagName`: element tag name. --- @@ -229,14 +236,13 @@ Running the bos-workspace dev server will start a local gateway with a standard bw dev --no-gateway ``` -However, there is an option to override this default gateway with a custom `/dist`. This is helpful when building widgets that utilize [custom VM elements](https://github.com/NEARBuilders/near-bos-webcomponent?tab=readme-ov-file#configuring-vm-custom-elements). To use this feature, use the `-g` flag with a path to the local custom distribution or link to package published on [nearfs](https://github.com/vgrichina/nearfs) or via cdn: +However, there is an option to override this default gateway with a custom `/dist`. This is helpful when building widgets that utilize [custom VM elements](https://github.com/NEARBuilders/near-bos-webcomponent?tab=readme-ov-file#configuring-vm-custom-elements). To use this feature, specify the gateway bundle url and the tag name in the `bos.config.json` file. ```cmd -bw dev -g path/to/dist -``` - -```cmd -bw dev -g https://ipfs.web4.near.page/ipfs/bafybeiancp5im5nfkdki3cfvo7ownl2knjovqh7bseegk4zvzsl4buryoi +"gateway": { + "bundleUrl": "https://ipfs.web4.near.page/ipfs/bafybeibe63hqugbqr4writdxgezgl5swgujay6t5uptw2px7q63r7crk2q/", + "tagName": "near-social-viewer" +} ``` This will automatically start the local gateway serving your widgets through the provided dist. diff --git a/examples/single/bos.config.json b/examples/single/bos.config.json index 273c159..7dec33c 100644 --- a/examples/single/bos.config.json +++ b/examples/single/bos.config.json @@ -8,5 +8,9 @@ "aliases": ["./aliases.testnet.json"], "index": "quickstart.testnet/widget/home" } - } + }, + "gateway": { + "bundleUrl": "https://ipfs.web4.near.page/ipfs/bafybeibe63hqugbqr4writdxgezgl5swgujay6t5uptw2px7q63r7crk2q/", + "tagName": "near-social-viewer" + } } diff --git a/lib/cli.ts b/lib/cli.ts index 0c576f9..6fe95de 100644 --- a/lib/cli.ts +++ b/lib/cli.ts @@ -26,7 +26,6 @@ async function run() { .option("-n, --network ", "network to build for", "mainnet") .option("-l, --loglevel ", "log level (ERROR, WARN, INFO, DEV, BUILD, DEBUG)", "DEV") .option("-p, --port ", "Port to run the server on", "8080") - .option("-g, --gateway ", "Path to custom gateway dist", true) .option("--no-gateway", "Disable the gateway") .option("--no-hot", "Disable hot reloading") .option("--no-open", "Disable opening the browser") @@ -62,7 +61,6 @@ async function run() { .option("-n, --network ", "network to build for", "mainnet") .option("-l, --loglevel ", "log level (ERROR, WARN, INFO, DEV, BUILD, DEBUG)") .option("-p, --port ", "Port to run the server on", "8080") - .option("-g, --gateway ", "Path to custom gateway dist", true) .option("--no-gateway", "Disable the gateway") .option("--no-hot", "Disable hot reloading") .option("--no-open", "Disable opening the browser") diff --git a/lib/config.ts b/lib/config.ts index b91f387..d5dba7f 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -2,6 +2,7 @@ import Joi from 'joi'; import { readJson } from '@/lib/utils/fs'; import { Network } from './types'; import path from 'path'; +import { GatewayConfig } from './dev'; export interface BaseConfig { account?: string; // default account to serve widgets from @@ -20,6 +21,7 @@ export interface BaseConfig { index?: string; // widget to use as index aliasPrefix?: string; // prefix to use for aliases, default is "alias" aliasesContainsPrefix?: boolean; // aliases keys contains prefix (default is false) + gateway?: GatewayConfig // gateway config object } interface NetworkConfig { @@ -62,6 +64,10 @@ const baseConfigSchema = Joi.object({ aliasPrefix: Joi.string().allow(null), aliasesContainsPrefix: Joi.boolean().allow(null), index: Joi.string().allow(null), + gateway: Joi.object({ + tagName: Joi.string(), + bundleUrl: Joi.string(), + }).and('tagName', 'bundleUrl').allow(null), }); const networkConfigSchema = Joi.object({ diff --git a/lib/dev.ts b/lib/dev.ts index e720055..0d4de13 100644 --- a/lib/dev.ts +++ b/lib/dev.ts @@ -17,16 +17,28 @@ var appDevOptions: null | DevOptions = null; let io: null | IoServer = null; let fileWatcher: null | FSWatcher = null; +export const DEFAULT_GATEWAY = { + enabled: true, + bundleUrl: "https://ipfs.web4.near.page/ipfs/bafybeibe63hqugbqr4writdxgezgl5swgujay6t5uptw2px7q63r7crk2q/", + tagName: "near-social-viewer" +}; + export type DevOptions = { port?: number; // port to run dev server hot?: boolean; // enable hot reloading open?: boolean; // open browser network?: Network; // network to use - gateway?: string | boolean; // path to custom gateway dist, or false to disable + gateway?: boolean; // path to custom gateway dist, or false to disable index?: string; // widget to use as index output?: string; // output directory }; +export type GatewayConfig = { + enabled: boolean; + tagName: string; + bundleUrl: string; +}; + /** * Build and watch app according to bos.config.json * @@ -38,8 +50,10 @@ export async function dev(src: string, dest: string, opts: DevOptions) { const dist = path.join(src, dest); const devJsonPath = path.join(dist, "bos-loader.json"); - // Build the app for the first time + // Build the app for the first timo + const config = await loadConfig(src, opts.network); + let devJson = await generateApp(src, dist, config, opts); await writeJson(devJsonPath, devJson); @@ -55,7 +69,10 @@ export async function dev(src: string, dest: string, opts: DevOptions) { appDevJsonPath = devJsonPath; opts.output = dist; appDevOptions = opts; - const server = startDevServer(appSrcs, appDists, appDevJsonPath, appDevOptions); + + const gatewayObject: GatewayConfig = buildGatewayObject(opts.gateway, config.gateway) + + const server = startDevServer(appSrcs, appDists, appDevJsonPath, appDevOptions, gatewayObject); // Start the socket server if hot reload is enabled if (opts.hot) { @@ -236,3 +253,22 @@ async function generateDevJson(src: string, config: BaseConfig): Promise { + startServer(server, opts, gateway, () => { const postData = JSON.stringify({ srcs: srcs.map((src) => path.resolve(src)), dists: dists.map((dist) => path.resolve(dist)) }); const options = { hostname: '127.0.0.1', @@ -96,8 +95,9 @@ export function startDevServer(srcs: string[], dists: string[], devJsonPath: str * (separated out to enable endpoint testing) * @param opts * @param devJsonPath + * @param gateway */ -export function createApp(devJsonPath: string, opts: DevOptions): Express.Application { +export function createApp(devJsonPath: string, opts: DevOptions, gateway: GatewayConfig): Express.Application { const app = express(); log.success("HTTP server setup successfully."); @@ -220,18 +220,15 @@ export function createApp(devJsonPath: string, opts: DevOptions): Express.Applic */ app.all('/api/proxy-rpc', proxyMiddleware(RPC_URL[opts.network])); - if (opts.gateway) { + if (gateway.enabled) { log.debug("Setting up gateway..."); if (opts.index) { - log.debug("Index provided. Using new gateway setup."); + // use new path - let gatewayUrl = typeof opts.gateway === 'string' ? opts.gateway : DEFAULT_REMOTE_GATEWAY_URL; - const isLocalPath = !gatewayUrl.startsWith('http'); - gatewayUrl = gatewayUrl.replace(/\/$/, ''); // remove trailing slash - opts.gateway = gatewayUrl; // standardize to url string + const isLocalPath = !gateway.bundleUrl.startsWith('http'); - initializeGateway(gatewayUrl, isLocalPath, opts, devJsonPath); + initializeGateway(gateway, isLocalPath, opts, devJsonPath); // Middleware to ensure gateway is initialized before handling requests app.use(async (req, res, next) => { @@ -255,7 +252,7 @@ export function createApp(devJsonPath: string, opts: DevOptions): Express.Applic log.debug(`Request for: ${req.path}`); if (isLocalPath) { - const fullUrl = path.join(__dirname, gatewayUrl, req.path); + const fullUrl = path.join(__dirname, gateway.bundleUrl, req.path); try { log.debug(`Attempting to serve file from local path: ${fullUrl}`); @@ -273,9 +270,9 @@ export function createApp(devJsonPath: string, opts: DevOptions): Express.Applic } } } else { - log.debug(`Proxying request to: ${gatewayUrl}${req.path}`); + log.debug(`Proxying request to: ${gateway.bundleUrl}${req.path}`); // Proxy the request to the remote gateway - proxy.web(req, res, { target: `${gatewayUrl}${req.path}`, agent: httpsAgent }); + proxy.web(req, res, { target: `${gateway.bundleUrl}${req.path}`, agent: httpsAgent }); } } else { // what about images? @@ -335,8 +332,8 @@ export function createApp(devJsonPath: string, opts: DevOptions): Express.Applic return app; } -function initializeGateway(gatewayUrl: string, isLocalPath: boolean, opts: DevOptions, devJsonPath: string) { - gatewayInitPromise = setupGateway(gatewayUrl, isLocalPath, opts, devJsonPath) +function initializeGateway(gateway: GatewayConfig, isLocalPath: boolean, opts: DevOptions, devJsonPath: string) { + gatewayInitPromise = setupGateway(gateway, isLocalPath, opts, devJsonPath) .then(() => { log.success("Gateway initialized successfully."); }) @@ -346,12 +343,12 @@ function initializeGateway(gatewayUrl: string, isLocalPath: boolean, opts: DevOp }); } -async function setupGateway(gatewayUrl: string, isLocalPath: boolean, opts: DevOptions, devJsonPath: string) { - log.debug(`Setting up ${isLocalPath ? "local " : ""}gateway: ${gatewayUrl}`); +async function setupGateway(gateway: GatewayConfig, isLocalPath: boolean, opts: DevOptions, devJsonPath: string) { + log.debug(`Setting up ${isLocalPath ? "local " : ""}gateway: ${gateway.bundleUrl}`); const manifestUrl = isLocalPath - ? path.join(gatewayUrl, "/asset-manifest.json") - : `${gatewayUrl}/asset-manifest.json`; + ? path.join(gateway.bundleUrl, "/asset-manifest.json") + : `${gateway.bundleUrl}/asset-manifest.json`; try { log.debug(`Fetching manifest from: ${manifestUrl}`); @@ -360,8 +357,8 @@ async function setupGateway(gatewayUrl: string, isLocalPath: boolean, opts: DevO log.debug(`Received manifest. Modifying HTML...`); const htmlContent = await readFile(path.join(__dirname, '../../public/index.html'), 'utf8'); - const dependencies = manifest.entrypoints.map((entrypoint: string) => isLocalPath ? `${entrypoint}` : `${gatewayUrl}/${entrypoint}`); - modifiedHtml = modifyIndexHtml(htmlContent, opts, dependencies); + const dependencies = manifest.entrypoints.map((entrypoint: string) => isLocalPath ? `${entrypoint}` : `${gateway.bundleUrl}/${entrypoint}`); + modifiedHtml = modifyIndexHtml(htmlContent, opts, dependencies, gateway); // log.debug(`Importing packages...`); <-- this used jpsm to create import map for wallet selector // modifiedHtml = await importPackages(modifiedHtml); // but didn't want it to run each time dev server started, so commented out @@ -402,10 +399,11 @@ async function fetchManifest(url: string): Promise { * Starts BosLoader Server and optionally opens gateway in browser * @param server http server * @param opts DevOptions + * @param gateway gateway object */ -export function startServer(server, opts, sendAddApps) { +export function startServer(server, opts, gateway, sendAddApps) { server.listen(opts.port, "127.0.0.1", () => { - if (opts.gateway && opts.open) { + if (gateway.enabled && opts.open) { // open gateway in browser let start = process.platform == "darwin" @@ -419,7 +417,7 @@ export function startServer(server, opts, sendAddApps) { log.log(` ┌─────────────────────────────────────────────────────────────┐ │ BosLoader Server is Up and Running │ - │ │${opts.gateway + │ │${gateway.enabled ? ` │ ➜ Local Gateway: \u001b[32mhttp://127.0.0.1:${opts.port}\u001b[0m │` : "" @@ -451,4 +449,4 @@ export function startServer(server, opts, sendAddApps) { process.exit(1); } }); -} +} \ No newline at end of file diff --git a/tests/unit/dev.ts b/tests/unit/dev.ts index 692876b..07dc403 100644 --- a/tests/unit/dev.ts +++ b/tests/unit/dev.ts @@ -1,6 +1,6 @@ import { buildApp } from "@/lib/build"; import { DEFAULT_CONFIG, loadConfig } from "@/lib/config"; -import { dev, DevOptions, addApps } from "@/lib/dev"; +import { dev, DevOptions, addApps, DEFAULT_GATEWAY } from "@/lib/dev"; import { Logger, LogLevel } from "@/lib/logger"; import { startDevServer } from "@/lib/server"; import { startSocket } from "@/lib/socket"; @@ -56,11 +56,13 @@ describe("dev", () => { expect(loadConfig).toHaveBeenCalledWith(mockSrc, mockOpts.network); }); - it("should call generateApp with src, dist, config, opts, and devJsonPath", async () => { + it("should call generateApp with src, dist, config, opts, gateway, and devJsonPath", async () => { await dev(mockSrc, "build", mockOpts); const mockDist = path.join(mockSrc, 'build'); const mockDevJsonPath = path.join(mockSrc, 'build', 'bos-loader.json'); - expect(startDevServer).toHaveBeenCalledWith([mockSrc], [mockDist], mockDevJsonPath, mockOpts); + const mockGateway = DEFAULT_GATEWAY; + + expect(startDevServer).toHaveBeenCalledWith([mockSrc], [mockDist], mockDevJsonPath, mockOpts, mockGateway); }); it("should start the socket server if hot reload is enabled", async () => { diff --git a/tests/unit/gateway.ts b/tests/unit/gateway.ts index 201958d..d66f99c 100644 --- a/tests/unit/gateway.ts +++ b/tests/unit/gateway.ts @@ -1,4 +1,4 @@ -import { DevOptions } from '@/lib/dev'; +import { DEFAULT_GATEWAY, DevOptions } from '@/lib/dev'; import { handleReplacements, modifyIndexHtml } from '@/lib/gateway'; import { Logger, LogLevel } from "@/lib/logger"; import { Network } from '@/lib/types'; @@ -50,7 +50,7 @@ describe("gateway", () => { it('adds script tags for dependencies', () => { const dependencies = ['dep1.js', 'dep2.js']; - const result = modifyIndexHtml(baseHtml, mockOpts, dependencies); + const result = modifyIndexHtml(baseHtml, mockOpts, dependencies, DEFAULT_GATEWAY); const dom = new JSDOM(result); const scripts = dom.window.document.querySelectorAll('script'); @@ -61,7 +61,7 @@ describe("gateway", () => { }); it('creates and configures near-social-viewer element', () => { - const result = modifyIndexHtml(baseHtml, mockOpts, []); + const result = modifyIndexHtml(baseHtml, mockOpts, [], DEFAULT_GATEWAY); const dom = new JSDOM(result); const viewer = dom.window.document.querySelector('near-social-viewer'); @@ -72,7 +72,7 @@ describe("gateway", () => { }); it('sets correct config attribute on near-social-viewer', () => { - const result = modifyIndexHtml(baseHtml, mockOpts, []); + const result = modifyIndexHtml(baseHtml, mockOpts, [], DEFAULT_GATEWAY); const dom = new JSDOM(result); const viewer = dom.window.document.querySelector('near-social-viewer'); @@ -82,7 +82,7 @@ describe("gateway", () => { }); it('appends near-social-viewer to the container', () => { - const result = modifyIndexHtml(baseHtml, mockOpts, []); + const result = modifyIndexHtml(baseHtml, mockOpts, [], DEFAULT_GATEWAY); const dom = new JSDOM(result); const container = dom.window.document.getElementById('bw-root'); @@ -97,7 +97,7 @@ describe("gateway", () => { network: 'mainnet' as Network, hot: false }; - const result = modifyIndexHtml(baseHtml, customOpts, []); + const result = modifyIndexHtml(baseHtml, customOpts, [], DEFAULT_GATEWAY); const dom = new JSDOM(result); const viewer = dom.window.document.querySelector('near-social-viewer'); @@ -108,4 +108,16 @@ describe("gateway", () => { const config = JSON.parse(viewer.getAttribute('config')); expect(config.dev.hotreload.enabled).toBe(false); }); + + it('uses the tag name from the gateway config', () => { + const tagName = "test-element" + const gatewayConfig = DEFAULT_GATEWAY; + gatewayConfig.tagName = tagName + + const result = modifyIndexHtml(baseHtml, mockOpts, [], gatewayConfig); + const dom = new JSDOM(result); + const container = dom.window.document.querySelector(tagName); + + expect(container.getAttribute('src')).toBe(mockOpts.index); + }); }); \ No newline at end of file diff --git a/tests/unit/server.ts b/tests/unit/server.ts index 1374d49..b6c538a 100644 --- a/tests/unit/server.ts +++ b/tests/unit/server.ts @@ -1,14 +1,15 @@ -import { DevOptions } from './../../lib/dev'; +import { buildGatewayObject, DEFAULT_GATEWAY, DevOptions } from '@/lib/dev'; import { Logger, LogLevel } from "@/lib/logger"; import { createApp, RPC_URL } from '@/lib/server'; import supertest from 'supertest'; import { TextEncoder } from 'util'; -import { Network } from './../../lib/types'; +import { Network } from '@/lib/types'; import { fetchJson } from "@near-js/providers"; import * as gateway from '@/lib/gateway'; import { vol } from 'memfs'; import path from 'path'; + jest.mock('fs', () => require('memfs').fs); jest.mock('fs/promises', () => require('memfs').fs.promises); jest.mock("@near-js/providers"); @@ -45,9 +46,9 @@ describe('createApp', () => { global.log = new Logger(LogLevel.DEV); - app = createApp(devJsonPath, opts); + app = createApp(devJsonPath, opts, DEFAULT_GATEWAY); - app = createApp(devJsonPath, opts); + app = createApp(devJsonPath, opts, DEFAULT_GATEWAY); }); afterEach(() => { @@ -57,14 +58,15 @@ describe('createApp', () => { }); it.skip('should set up the app correctly when opts.gateway is a valid local path', () => { - const mockGatewayPath = "/mock_gateway_1"; - opts.gateway = `${mockGatewayPath}/dist`; - vol.mkdirSync(path.join(mockGatewayPath, 'dist'), { recursive: true }); - vol.writeFileSync(path.join(mockGatewayPath, 'dist', 'index.html'), ''); + const gatewayObject = DEFAULT_GATEWAY + gatewayObject.bundleUrl = '/mock_gateway_1/dist' + + vol.mkdirSync(path.join(gatewayObject.bundleUrl, 'dist'), { recursive: true }); + vol.writeFileSync(path.join(gatewayObject.bundleUrl, 'dist', 'index.html'), ''); jest.spyOn(gateway, 'modifyIndexHtml').mockReturnValue('modified'); - app = createApp(devJsonPath, opts); + app = createApp(devJsonPath, opts, gatewayObject); expect(app).toBeDefined(); return supertest(app) @@ -75,12 +77,14 @@ describe('createApp', () => { }); it.skip('should log an error when opts.gateway is an invalid local path', () => { - const mockGatewayPath = '/invalid/gateway/path'; - opts.gateway = mockGatewayPath; + const gatewayObject = DEFAULT_GATEWAY + gatewayObject.bundleUrl = '/invalid/gateway/path'; + + buildGatewayObject(true, gatewayObject) const logSpy = jest.spyOn(global.log, 'error'); - app = createApp(devJsonPath, opts); + app = createApp(devJsonPath, opts, gatewayObject); expect(app).toBeDefined(); expect(logSpy).toHaveBeenCalledWith("Gateway not found. Skipping..."); }); From 94731011e1a76fd2fa0e603696ca552c524404a4 Mon Sep 17 00:00:00 2001 From: bbface <152608874+bb-face@users.noreply.github.com> Date: Tue, 13 Aug 2024 22:00:15 +0100 Subject: [PATCH 2/5] 100 implement upload command (#148) * Add upload folders script * Add support for nested folders * Smart contract panic * Fix data creation + add test * Merge uplaod functions + README --- README.md | 10 +++++- lib/config.ts | 6 ++++ lib/deploy.ts | 71 +++++++++++++++++++++++++++++------------ lib/utils/fs.ts | 29 ++++++++++++++++- tests/unit/devNoMock.ts | 65 ++++++++++++++++++++++++++++++++++++- 5 files changed, 158 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 61037da..f95fa0d 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,15 @@ Commands: **Command:** `deploy` -Deploys an app in the workspace via a convenient wrapper to [bos-cli-rs](https://github.com/bos-cli-rs/bos-cli-rs). +Deploys an app in the workspace via a convenient wrapper to [bos-cli-rs](https://github.com/bos-cli-rs/bos-cli-rs). It's also possible to add an optional string array in the `bos.config.json` to specify the data to upload: + +``` + "data": { + "include": ["folder"] + } +``` + +The upload script will bundle all the json files inside the specified folder and upload the data with the app. ```cmd bw deploy [app name] --deploy-account-id [deployAccountId] --signer-account-id [signerAccountId] --signer-public-key [signerPublicKey] --signer-private-key [signerPrivateKey] diff --git a/lib/config.ts b/lib/config.ts index d5dba7f..f09e57b 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -21,6 +21,9 @@ export interface BaseConfig { index?: string; // widget to use as index aliasPrefix?: string; // prefix to use for aliases, default is "alias" aliasesContainsPrefix?: boolean; // aliases keys contains prefix (default is false) + data?: { + include: string[]; // specify folder's array to upload along with widget + } gateway?: GatewayConfig // gateway config object } @@ -64,6 +67,9 @@ const baseConfigSchema = Joi.object({ aliasPrefix: Joi.string().allow(null), aliasesContainsPrefix: Joi.boolean().allow(null), index: Joi.string().allow(null), + data: Joi.object({ + include: Joi.array().items(Joi.string()).min(1).required() + }).optional(), gateway: Joi.object({ tagName: Joi.string(), bundleUrl: Joi.string(), diff --git a/lib/deploy.ts b/lib/deploy.ts index 6f1dcd7..9447be9 100644 --- a/lib/deploy.ts +++ b/lib/deploy.ts @@ -5,7 +5,7 @@ import fs from "fs"; import { buildApp } from "@/lib/build"; import { readConfig } from "@/lib/config"; import { Network } from "@/lib/types"; -import { move, pathExists, readdir, remove } from "@/lib/utils/fs"; +import { move, pathExists, processDirectory, readdir, remove } from "@/lib/utils/fs"; import { readWorkspace } from "@/lib/workspace"; import { SOCIAL_CONTRACT } from './server'; @@ -108,12 +108,22 @@ export async function deployAppCode(src: string, dist: string, opts: DeployOptio }); } -export async function deployAppData(appName: string, opts: DeployOptions) { - const config = await readConfig(path.join(appName, "bos.config.json"), opts.network); - const BOS_SIGNER_ACCOUNT_ID = config.accounts.signer || opts.signerAccountId || config.account; +export async function deployAppData( + appName: string, + opts: DeployOptions +) { + const config = await readConfig( + path.join(appName, "bos.config.json"), + opts.network + ); + + const BOS_SIGNER_ACCOUNT_ID = + config.accounts.signer || opts.signerAccountId || config.account; if (!BOS_SIGNER_ACCOUNT_ID) { - console.log(`App account is not defined for ${appName}. Skipping data upload`); + console.log( + `App account is not defined for ${appName}. Skipping data upload` + ); return; } @@ -123,26 +133,34 @@ export async function deployAppData(appName: string, opts: DeployOptions) { ); const args = { data: JSON.parse(dataJSON) }; - const argsBase64 = Buffer.from(JSON.stringify(args)).toString("base64"); - - const BOS_SIGNER_PUBLIC_KEY = opts?.signerPublicKey; - const BOS_SIGNER_PRIVATE_KEY = opts?.signerPrivateKey; - const automaticSignIn = [ - "sign-with-plaintext-private-key", - "--signer-public-key", - BOS_SIGNER_PUBLIC_KEY, - "--signer-private-key", - BOS_SIGNER_PRIVATE_KEY, - "send" - ] + if (config.data?.include) { + if (!Array.isArray(config.data.include) || config.data.include.length === 0) + throw new Error( + "Config must contain a data.include array with at least one folder" + ); + + const result = {}; + + for (const folder of config.data.include) { + const folderName = path.basename(folder); + result[folderName] = {}; + await processDirectory(folder, "", result[folderName]); + } + + Object.assign(args.data[config.account], result); + } + + const argsBase64 = Buffer.from(JSON.stringify(args)).toString("base64"); let command = [ "near-cli-rs", "contract", "call-function", "as-transaction", - opts.network === "mainnet" ? SOCIAL_CONTRACT.mainnet : SOCIAL_CONTRACT.testnet, + opts.network === "mainnet" + ? SOCIAL_CONTRACT.mainnet + : SOCIAL_CONTRACT.testnet, "set", "base64-args", `${argsBase64}`, @@ -153,10 +171,23 @@ export async function deployAppData(appName: string, opts: DeployOptions) { "sign-as", BOS_SIGNER_ACCOUNT_ID, "network-config", - opts.network, + opts.network, + ]; + + const BOS_SIGNER_PUBLIC_KEY = opts?.signerPublicKey; + const BOS_SIGNER_PRIVATE_KEY = opts?.signerPrivateKey; + + const automaticSignIn = [ + "sign-with-plaintext-private-key", + "--signer-public-key", + BOS_SIGNER_PUBLIC_KEY, + "--signer-private-key", + BOS_SIGNER_PRIVATE_KEY, + "send", ]; - if (BOS_SIGNER_PUBLIC_KEY && BOS_SIGNER_PRIVATE_KEY) command = command.concat(automaticSignIn) + if (BOS_SIGNER_PUBLIC_KEY && BOS_SIGNER_PRIVATE_KEY) + command = command.concat(automaticSignIn); const deployProcess = spawn("npx", command, { cwd: path.join(appName, DEPLOY_DIST_FOLDER), diff --git a/lib/utils/fs.ts b/lib/utils/fs.ts index 52ef78b..461af08 100644 --- a/lib/utils/fs.ts +++ b/lib/utils/fs.ts @@ -1,4 +1,5 @@ import { copy, ensureDir, move, outputFile, pathExists, readdir, readFile, readJson, remove, writeJson, existsSync, promises } from 'fs-extra'; +import { readdirSync, readFileSync } from 'fs'; import path from 'path'; async function loopThroughFiles(pwd: string, callback: (file: string) => Promise) { @@ -16,4 +17,30 @@ async function loopThroughFiles(pwd: string, callback: (file: string) => Promise } } -export { copy, ensureDir, loopThroughFiles, move, outputFile, pathExists, readdir, readFile, readJson, remove, writeJson, existsSync, promises }; +async function processDirectory(baseDir, currentDir, result) { + const files = await readdirSync(path.join(baseDir, currentDir), { withFileTypes: true }); + for (const file of files) { + const relativePath = path.join(currentDir, file.name); + const fullPath = path.join(baseDir, relativePath); + + if (file.isDirectory()) { + await processDirectory(baseDir, relativePath, result); + } else if (path.extname(file.name).toLowerCase() === '.json') { + try { + const fileContent = await readFileSync(fullPath, 'utf8'); + const jsonContent = JSON.parse(fileContent); + let key; + if (currentDir === '') { + key = path.basename(file.name, '.json'); + } else { + key = path.join(currentDir, path.basename(file.name, '.json')).replace(/[\\/]/g, '.'); + } + result[key] = { "": JSON.stringify(jsonContent) }; + } catch (error) { + console.error(`Error processing file ${fullPath}:`, error); + } + } + } +} + +export { copy, ensureDir, loopThroughFiles, move, outputFile, pathExists, readdir, readFile, readJson, remove, writeJson, existsSync, promises, processDirectory }; diff --git a/tests/unit/devNoMock.ts b/tests/unit/devNoMock.ts index 5613260..ddb0322 100644 --- a/tests/unit/devNoMock.ts +++ b/tests/unit/devNoMock.ts @@ -1,6 +1,7 @@ import { startFileWatcher } from "@/lib/watcher"; import path from "path"; import fs from "fs"; +import { processDirectory } from "@/lib/utils/fs"; describe("File Watcher Tests", () => { let watcher; @@ -37,4 +38,66 @@ describe("File Watcher Tests", () => { fs.rmSync(tempDirPath, { recursive: true, force: true }); } }); -}); \ No newline at end of file +}); + +describe('Folder structure processing', () => { + const tempDirPath = path.join(__dirname, 'temp_test_dir'); + const testFolderPath = path.join(tempDirPath, 'test'); + const nestedTestFolderPath = path.join(testFolderPath, 'nestedTest'); + const test1FolderPath = path.join(tempDirPath, 'test1'); + + beforeAll(() => { + fs.mkdirSync(tempDirPath, { recursive: true }); + fs.mkdirSync(testFolderPath, { recursive: true }); + fs.mkdirSync(nestedTestFolderPath, { recursive: true }); + fs.mkdirSync(test1FolderPath, { recursive: true }); + + fs.writeFileSync( + path.join(testFolderPath, 'file.json'), + JSON.stringify({ data: "this is test" }) + ); + fs.writeFileSync( + path.join(nestedTestFolderPath, 'nestedFile.json'), + JSON.stringify({ data: "this is a nested folder", data2: "other data" }) + ); + fs.writeFileSync( + path.join(test1FolderPath, 'file1.json'), + JSON.stringify({ data: "this is test1" }) + ); + }); + + it("should build the correct object based on folder structure", async () => { + const config = { + data: { + include: [tempDirPath] + }, + account: 'myaccount' + }; + + const result = {}; + + for (const folder of config.data.include) { + const folderName = path.basename(folder); + result[folderName] = {}; + await processDirectory(folder, '', result[folderName]); + } + + expect(result).toEqual({ + 'temp_test_dir': { + 'test.nestedTest.nestedFile': { + '': JSON.stringify({ data: "this is a nested folder", data2: "other data" }) + }, + 'test.file': { + '': JSON.stringify({ data: "this is test" }) + }, + 'test1.file1': { + '': JSON.stringify({ data: "this is test1" }) + } + } + }); + }); + + afterAll(() => { + fs.rmSync(tempDirPath, { recursive: true, force: true }); + }); +}); From 529c53e87fb23eba17bdbf5cbf30e4c7258f399c Mon Sep 17 00:00:00 2001 From: Elliot Braem <16282460+elliotBraem@users.noreply.github.com> Date: Wed, 14 Aug 2024 02:08:10 -0500 Subject: [PATCH 3/5] add issue template and update readme (#149) --- .github/ISSUE_TEMPLATE/BOUNTY.yml | 131 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/bug_report.yml | 34 ++++++ .github/ISSUE_TEMPLATE/feature_request.yml | 17 +++ README.md | 131 ++++++++++++++------- 4 files changed, 272 insertions(+), 41 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/BOUNTY.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/BOUNTY.yml b/.github/ISSUE_TEMPLATE/BOUNTY.yml new file mode 100644 index 0000000..b3f9a80 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BOUNTY.yml @@ -0,0 +1,131 @@ +name: "Simple Bounty" +description: "Use this template to create a HEROES Simple Bounty via Github bot" +title: "Bounty: " +labels: ["bounty"] +assignees: heroes-bot-test +body: + - type: markdown + attributes: + value: | + Hi! Let's set up your bounty! Please don't change the template - @heroes-bot-test won't be able to help you. + + - type: dropdown + id: type + attributes: + label: What talent are you looking for? + options: + - Marketing + - Development + - Design + - Other + - Content + - Research + - Audit + + - type: textarea + id: description + attributes: + label: What you need to be done? + + - type: dropdown + id: tags + attributes: + label: Tags + description: Add tags that match the topic of the work + multiple: true + options: + - API + - Blockchain + - Community + - CSS + - DAO + - dApp + - DeFi + - Design + - Documentation + - HTML + - Javascript + - NFT + - React + - Rust + - Smart contract + - Typescript + - UI/UX + - web3 + - Translation + - Illustration + - Branding + - Copywriting + - Blogging + - Editing + - Video Creation + - Social Media + - Graphic Design + - Transcription + - Product Design + - Artificial Intelligence + - Quality Assurance + - Risk Assessment + - Security Audit + - Bug Bounty + - Code Review + - Blockchain Security + - Smart Contract Testing + - Penetration Testing + - Vulnerability Assessment + - BOS + - News + - Hackathon + - NEARCON2023 + - NEARWEEK + + - type: input + id: deadline + attributes: + label: Deadline + description: "Set a deadline for your bounty. Please enter the date in format: DD.MM.YYYY" + placeholder: "19.05.2027" + + - type: dropdown + id: currencyType + attributes: + label: Currency + description: What is the currency you want to pay? + options: + - USDC.e + - USDT.e + - DAI + - wNEAR + - USDt + - XP + - marmaj + - NEKO + - JUMP + - USDC + - NEARVIDIA + default: 0 + validations: + required: true + + - type: input + id: currencyAmount + attributes: + label: Amount + description: How much it will be cost? + + - type: markdown + attributes: + value: "## Advanced settings" + + - type: checkboxes + id: kyc + attributes: + label: KYC + description: "Use HEROES' KYC Verification, only applicants who passed HEROES' KYC can apply and work on this bounty!" + options: + - label: Use KYC Verification + + - type: markdown + attributes: + value: | + ### This cannot be changed once the bounty is live! diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..68d5622 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,34 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug"] +assignees: [] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: How can we reproduce the bug? + description: If you can make the bug happen again, please share the steps involved. If possible please also include a screenshot or a screen recording to help us better understand and resolve the issue. + validations: + required: false + - type: dropdown + id: browsers + attributes: + label: What browsers are you seeing the problem on? + multiple: true + options: + - Firefox + - Chrome + - Safari + - Microsoft Edge diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..4e2d3ca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,17 @@ +name: Feature request +description: File a feature request +title: "[Feature]: " +labels: ["enhancement"] +assignees: [] +body: + - type: markdown + attributes: + value: | + Have an idea for a feature or change? + - type: textarea + id: description + attributes: + label: What's the feature? + description: Describe the feature, who it would help, and link to any examples from other apps. + validations: + required: true diff --git a/README.md b/README.md index f95fa0d..99d866f 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,73 @@ -
+ + + + -# bos-workspace +
-🚧 **Warning: This library has recently undergone a major refactor.** 🚧 +

bos-workspace

-**If this is not your first time using bos-workspace, read the [migration guide](./MIGRATION_GUIDE.md). The legacy documentation for v0.0.1-alpha.6 can be found [here](https://github.com/NEARBuilders/bos-workspace/tree/version/0.0.1-alpha.6).** +

+ Local workspace for NEAR BOS development +

`bos-workspace` is a comprehensive toolset designed to simplify the development and deployment of [NEAR components](https://docs.near.org/bos/tutorial/quickstart) and applications. With support for hot reload, TypeScript, and multi-app management, it caters to developers looking for an efficient and scalable developer environment. +> [!WARNING] +> 🚧 **Notice: This library has recently undergone a major refactor.** 🚧 +> +> **If this is not your first time using bos-workspace, read the [migration guide](./MIGRATION_GUIDE.md). The legacy documentation for v0.0.1-alpha.6 can be found [here](https://github.com/NEARBuilders/bos-workspace/tree/version/0.0.1-alpha.6).** + +
+ Table of Contents + +- [Quickstart](#quickstart) +- [Usage](#usage) +- [Configuration](#configuration) + - [Base Configuration](#base-configuration) + - [Network Overrides](#network-overrides) + - [Aliases](#aliases) + - [Custom alias prefix](#custom-alias-prefix) +- [Customizing the Gateway](#customizing-the-gateway) +- [Deploying to Web4](#deploying-to-web4) +- [Commands](#commands) +- [Deployment](#deployment) + - [Usage (CLI)](#usage-cli) + - [Usage (Git Workflow)](#usage-git-workflow) + - [Prerequisites](#prerequisites) + - [Mainnet](#mainnet) + - [Testnet](#testnet) +- [API Endpoints](#api-endpoints) + - [Gateway Frontend](#gateway-frontend) + - [Loader API](#loader-api) + - [WebSocket](#websocket) + - [Proxy RPC](#proxy-rpc) +- [Contributing](#contributing) + +
+ ## Quickstart To begin, either: -* [Use the template repository](https://github.com/new?template_name=quickstart&template_owner=NEARBuilders) with quickstart app, preconfigured git workflows, and playwright test suite +- [Use the template repository](https://github.com/new?template_name=quickstart&template_owner=NEARBuilders) with quickstart app, preconfigured git workflows, and playwright test suite -* Use the init command for an empty workspace: +- Use the init command for an empty workspace: ```cmd npx bos-workspace init ``` -* Clone widgets from an existing [account](https://near.social/mob.near/widget/Everyone): +- Clone widgets from an existing [account](https://near.social/mob.near/widget/Everyone): ```cmd npx bos-workspace clone [accountId] [dest] npx bos-workspace dev [dest | accountId] ``` -* Or install `bos-workspace` within an existing project: +- Or install `bos-workspace` within an existing project: ```cmd yarn add -D bos-workspace @@ -41,7 +79,7 @@ and ensure the proper workspace [structure and usage](#usage). `bos-workspace` supports both multi and single app development because of `Apps` and `Workspaces`: -* **App**: which belong to an Account, described by a `bos.config.json`. A structure may look like this: +- **App**: which belong to an Account, described by a `bos.config.json`. A structure may look like this: ```txt app.near/ @@ -58,7 +96,7 @@ where the content of `bos.config.json` is (at least): } ``` -* **Workspace**: may hold multiple apps, described by a `bos.workspace.json` +- **Workspace**: may hold multiple apps, described by a `bos.workspace.json` ```txt apps/ @@ -124,20 +162,20 @@ A fully featured config may look like this: The `bos.config.json` file consists of a base configuration that defines default values and settings for the BOS environment. -* `account`: (Optional) Specifies the default account to serve widgets from. If not provided, the default value is set to `"bos.workspace"`. -* `accounts`: (Optional) Defines account configuration options for the `deploy` command. - * `deploy`: Specifies the account to deploy widgets to. - * `signer`: Specifies the account to sign the transaction. -* `ipfs`: (Optional) Configures IPFS settings for uploading and using local assets. - * `gateway`: IPFS gateway to use for accessing files. Default value is `"https://ipfs.near.social/ipfs"`. - * `uploadApi`: IPFS API endpoint to upload to. Default value is `"https://ipfs.near.social/add"`. - * `uploadApiHeaders`: Any additional headers to send with IPFS upload API requests. -* `format`: (Optional) Indicates whether to format code on build. Default value is `true`. -* `aliases`: (Optional) Provides a list of alias files to use for replacing network-specific values with correct overrides. -* `index`: (Optional) Default widget src to use when using a custom gateway dist. -* `gateway`: (Optional) Configures gateway object. - * `bundleUrl`: gateway url. - * `tagName`: element tag name. +- `account`: (Optional) Specifies the default account to serve widgets from. If not provided, the default value is set to `"bos.workspace"`. +- `accounts`: (Optional) Defines account configuration options for the `deploy` command. + - `deploy`: Specifies the account to deploy widgets to. + - `signer`: Specifies the account to sign the transaction. +- `ipfs`: (Optional) Configures IPFS settings for uploading and using local assets. + - `gateway`: IPFS gateway to use for accessing files. Default value is `"https://ipfs.near.social/ipfs"`. + - `uploadApi`: IPFS API endpoint to upload to. Default value is `"https://ipfs.near.social/add"`. + - `uploadApiHeaders`: Any additional headers to send with IPFS upload API requests. +- `format`: (Optional) Indicates whether to format code on build. Default value is `true`. +- `aliases`: (Optional) Provides a list of alias files to use for replacing network-specific values with correct overrides. +- `index`: (Optional) Default widget src to use when using a custom gateway dist. +- `gateway`: (Optional) Configures gateway object. + - `bundleUrl`: gateway url. + - `tagName`: element tag name. --- @@ -145,9 +183,9 @@ The `bos.config.json` file consists of a base configuration that defines default The `bos.config.json` file supports network configuration overrides of this base configuration, allowing developers to specify different settings for specific networks (e.g., mainnet, testnet). -* `overrides`: (Optional) Defines overrides for network-specific configurations. These values are used via the `-n` flag in commands, respectivly: - * `mainnet` - * `testnet` +- `overrides`: (Optional) Defines overrides for network-specific configurations. These values are used via the `-n` flag in commands, respectivly: + - `mainnet` + - `testnet` --- @@ -155,11 +193,11 @@ The `bos.config.json` file supports network configuration overrides of this base When working with values that differ accross different networks, developers can define aliases in separate JSON files according to environment. These aliases are replaced during build. -* **Account**: Defines the "owner" of the widgets in the workspace, according to network. - * Pattern: `{config_account}` -* **Aliases**: Defines patterns for replacing other account and contract references. These are particularly useful for widget sources accross environments, such as using mob.near for mainnet, and mike.testnet for testnet. - * Pattern: `${alias_key}` ( note that you may also have other prefixes than `alias_` by configuring the `aliasPrefix` property ) - * Example: +- **Account**: Defines the "owner" of the widgets in the workspace, according to network. + - Pattern: `{config_account}` +- **Aliases**: Defines patterns for replacing other account and contract references. These are particularly useful for widget sources accross environments, such as using mob.near for mainnet, and mike.testnet for testnet. + - Pattern: `${alias_key}` ( note that you may also have other prefixes than `alias_` by configuring the `aliasPrefix` property ) + - Example: ```json { @@ -209,7 +247,6 @@ If your aliases are prefixed with another keyword than `alias`, you may configur and then with your `aliases.mainnet.json` like this: - ```json { "REPL_NAME": "world" @@ -299,7 +336,7 @@ Commands: Deploys an app in the workspace via a convenient wrapper to [bos-cli-rs](https://github.com/bos-cli-rs/bos-cli-rs). It's also possible to add an optional string array in the `bos.config.json` to specify the data to upload: -``` +```json "data": { "include": ["folder"] } @@ -311,16 +348,16 @@ The upload script will bundle all the json files inside the specified folder and bw deploy [app name] --deploy-account-id [deployAccountId] --signer-account-id [signerAccountId] --signer-public-key [signerPublicKey] --signer-private-key [signerPrivateKey] ``` -* `[app name]`: Name of the app to be deployed. Assumed to be the current app in App structure (bos.config.json), but is required when using the Workspace structure (bos.workspace.json); this should match the name of the App's directory. -* `--deploy-account-id ` (Optional): Account under which component code should be deployed. Defaults to `config.account`, or will use `config.accounts.deploy` if specified. +- `[app name]`: Name of the app to be deployed. Assumed to be the current app in App structure (bos.config.json), but is required when using the Workspace structure (bos.workspace.json); this should match the name of the App's directory. +- `--deploy-account-id ` (Optional): Account under which component code should be deployed. Defaults to `config.account`, or will use `config.accounts.deploy` if specified. -* `--signer-account-id ` (Optional): Account which will be used for signing deploy transactions, frequently the same as deploy-account-id. Defaults to `config.account`, or will use `config.accounts.deploy` if specified. +- `--signer-account-id ` (Optional): Account which will be used for signing deploy transactions, frequently the same as deploy-account-id. Defaults to `config.account`, or will use `config.accounts.deploy` if specified. -* `--signer-public-key ` (Optional): Public key for signing transactions in the format: `ed25519:`. Will default to interactive [near-cli-rs](https://github.com/near/near-cli-rs) if not provided. +- `--signer-public-key ` (Optional): Public key for signing transactions in the format: `ed25519:`. Will default to interactive [near-cli-rs](https://github.com/near/near-cli-rs) if not provided. -* `--signer-private-key ` (Optional): Private key for signing transactions in the format: `ed25519:`. Will default to interactive [near-cli-rs](https://github.com/near/near-cli-rs) if not provided. +- `--signer-private-key ` (Optional): Private key for signing transactions in the format: `ed25519:`. Will default to interactive [near-cli-rs](https://github.com/near/near-cli-rs) if not provided. -* `-n, --network ` (Optional): Network to deploy for (default: "mainnet"). +- `-n, --network ` (Optional): Network to deploy for (default: "mainnet"). ### Usage (Git Workflow) @@ -410,4 +447,16 @@ A running `bos-workspace` server exposes several endpoints for interacting with ## Contributing -Read [CONTRIBUTING](./CONTRIBUTING.md) +Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +If you're interested in contributing to this project, please read the [contribution guide](./CONTRIBUTING). + + From 74d34ae6ac4095d422c18e9bec5799b947af417c Mon Sep 17 00:00:00 2001 From: Elliot Braem <16282460+elliotBraem@users.noreply.github.com> Date: Sat, 28 Sep 2024 17:18:35 -0400 Subject: [PATCH 4/5] add task (#151) --- .github/ISSUE_TEMPLATE/task.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/task.yml diff --git a/.github/ISSUE_TEMPLATE/task.yml b/.github/ISSUE_TEMPLATE/task.yml new file mode 100644 index 0000000..431e22d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/task.yml @@ -0,0 +1,27 @@ +name: Task +description: File a task +title: "[Task]: " +labels: ["enabler"] +assignees: [] +body: + - type: textarea + id: overview + attributes: + label: Overview + description: Provide a brief overview of the task to be done, including who will benefit from it. + validations: + required: true + - type: textarea + id: details + attributes: + label: Details + description: Describe the task in detail, including any specific requirements and examples from other applications if available. + validations: + required: false + - type: textarea + id: acceptance-criteria + attributes: + label: Acceptance Criteria + description: Define the criteria that must be met for the task to be considered complete. + validations: + required: false From 4d945f1c8b065a5d4db5611d7f3a7749ee4c3ba2 Mon Sep 17 00:00:00 2001 From: Elliot Braem <16282460+elliotBraem@users.noreply.github.com> Date: Wed, 2 Oct 2024 08:52:25 -0400 Subject: [PATCH 5/5] Update default gateway bundle (#152) * fix local dev * remove pnpm --- lib/dev.ts | 2 +- lib/server.ts | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/dev.ts b/lib/dev.ts index 0d4de13..0852e4c 100644 --- a/lib/dev.ts +++ b/lib/dev.ts @@ -19,7 +19,7 @@ let fileWatcher: null | FSWatcher = null; export const DEFAULT_GATEWAY = { enabled: true, - bundleUrl: "https://ipfs.web4.near.page/ipfs/bafybeibe63hqugbqr4writdxgezgl5swgujay6t5uptw2px7q63r7crk2q/", + bundleUrl: "https://ipfs.web4.near.page/ipfs/bafybeif7ouv5ehif36r6x3eugd3ylh6xyh24a22bbtoxeedwv5d6z45b64/", tagName: "near-social-viewer" }; diff --git a/lib/server.ts b/lib/server.ts index 84da8fe..64d09e9 100644 --- a/lib/server.ts +++ b/lib/server.ts @@ -163,13 +163,9 @@ export function createApp(devJsonPath: string, opts: DevOptions, gateway: Gatewa return async (req: Request, res: Response, _) => { let json = {}; - log.debug(`RPC Request: ${JSON.stringify(req.body)}`); - try { // Make a request to the target rpc json = await fetchJson(proxyUrl, JSON.stringify(req.body)); - - log.debug(`RPC Response: ${json}`); } catch (err) { log.error(err.stack || err.message); return res.status(500).send('Proxy request failed'); @@ -188,7 +184,7 @@ export function createApp(devJsonPath: string, opts: DevOptions, gateway: Gatewa ) { const social_get_key = JSON.parse(atob(params.args_base64)).keys[0]; - log.debug(`Replace with local components for key: ${social_get_key}`); + log.debug(`Redirecting to local component with key: ${social_get_key}`); const devComponents = await readJson(devJsonPath).then( (devJson: DevJson) => { @@ -249,13 +245,11 @@ export function createApp(devJsonPath: string, opts: DevOptions, gateway: Gatewa res.type('text/html').send(modifiedHtml); } else if (path.extname(req.path) === '.js' || path.extname(req.path) === '.css') { // Proxy requests for JS and CSS files - log.debug(`Request for: ${req.path}`); - if (isLocalPath) { - const fullUrl = path.join(__dirname, gateway.bundleUrl, req.path); + const fullUrl = path.join(process.cwd(), gateway.bundleUrl, req.path); try { - log.debug(`Attempting to serve file from local path: ${fullUrl}`); + log.debug(`Serving file from local path: ${fullUrl}`); // Attempt to serve the file from the local path await promises.access(fullUrl); res.sendFile(fullUrl); @@ -347,7 +341,7 @@ async function setupGateway(gateway: GatewayConfig, isLocalPath: boolean, opts: log.debug(`Setting up ${isLocalPath ? "local " : ""}gateway: ${gateway.bundleUrl}`); const manifestUrl = isLocalPath - ? path.join(gateway.bundleUrl, "/asset-manifest.json") + ? path.join(process.cwd(), gateway.bundleUrl, "/asset-manifest.json") : `${gateway.bundleUrl}/asset-manifest.json`; try {