Compare commits

...

22 Commits

Author SHA1 Message Date
semantic-release-bot fcded7350d chore(release): 0.1.0-develop.5 [skip ci]
# [0.1.0-develop.5](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.4...v0.1.0-develop.5) (2023-09-03)

### Bug Fixes

* need to slice out the key type byte ([578d965](578d965550))
2023-09-03 03:14:11 +00:00
Derrick Hammer c825f740bd
Merge remote-tracking branch 'origin/develop' into develop 2023-09-02 23:12:46 -04:00
Derrick Hammer 578d965550
fix: need to slice out the key type byte 2023-09-02 23:12:42 -04:00
Derrick Hammer ca5c983cbb
refactor: use decodeCid 2023-09-02 23:12:27 -04:00
Derrick Hammer 01858e6579
dep: update libweb 2023-09-02 23:12:05 -04:00
semantic-release-bot 329ab925ce chore(release): 0.1.0-develop.4 [skip ci]
# [0.1.0-develop.4](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.3...v0.1.0-develop.4) (2023-09-02)

### Bug Fixes

* only submit a new registry entry if the data has changed ([421cf81](421cf81f36))
2023-09-02 12:59:15 +00:00
Derrick Hammer f26fa8a6a9
Merge remote-tracking branch 'origin/develop' into develop 2023-09-02 08:58:22 -04:00
Derrick Hammer 421cf81f36
fix: only submit a new registry entry if the data has changed 2023-09-02 08:58:18 -04:00
semantic-release-bot 4bf00ff7fa chore(release): 0.1.0-develop.3 [skip ci]
# [0.1.0-develop.3](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.2...v0.1.0-develop.3) (2023-09-02)

### Bug Fixes

* need to use the sre.pk not cidBytes ([232669e](232669e776))
2023-09-02 12:44:56 +00:00
Derrick Hammer 0d64ec45f2
Merge remote-tracking branch 'origin/develop' into develop 2023-09-02 08:43:58 -04:00
Derrick Hammer 232669e776
fix: need to use the sre.pk not cidBytes 2023-09-02 08:43:53 -04:00
semantic-release-bot 7f46d47ce4 chore(release): 0.1.0-develop.2 [skip ci]
# [0.1.0-develop.2](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.1...v0.1.0-develop.2) (2023-09-02)

### Bug Fixes

* re-encode cid to be a webapp ([8e963d4](8e963d4b04))

### Features

* add support for creating a resolver CID for the app if APP_SEED is not false ([b03234e](b03234e38e))
2023-09-02 11:30:25 +00:00
Derrick Hammer 388c67d818
Merge remote-tracking branch 'origin/develop' into develop 2023-09-02 07:29:31 -04:00
Derrick Hammer 8e963d4b04
fix: re-encode cid to be a webapp 2023-09-02 07:29:26 -04:00
Derrick Hammer b03234e38e
feat: add support for creating a resolver CID for the app if APP_SEED is not false 2023-09-02 07:27:47 -04:00
semantic-release-bot 48dd3481b8 chore(release): 0.1.0-develop.1 [skip ci]
# [0.1.0-develop.1](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.0.1...v0.1.0-develop.1) (2023-08-15)

### Features

* initial version ([5de6422](5de6422a16))
2023-08-15 21:57:28 +00:00
Derrick Hammer 458a809c1d
ci: add semantic-release script 2023-08-15 17:56:28 -04:00
Derrick Hammer cd91d929b1
ci: setup 2023-08-15 17:42:31 -04:00
Derrick Hammer c2f7ac4317
ci: add .presetterrc.json 2023-08-15 17:34:15 -04:00
Derrick Hammer a429dc4bd8
ci: add npm-shrinkwrap.json 2023-08-15 17:33:50 -04:00
Derrick Hammer 9294a4abb0
ci: add repo and npm config to package.json 2023-08-15 17:32:48 -04:00
Derrick Hammer 5de6422a16
feat: initial version 2023-08-15 17:28:46 -04:00
7 changed files with 19153 additions and 0 deletions

13
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Build/Publish
on:
push:
branches:
- master
- develop
- develop-*
jobs:
main:
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
secrets: inherit

5
.presetterrc.json Normal file
View File

@ -0,0 +1,5 @@
{
"preset": [
"@lumeweb/node-library-preset"
]
}

39
CHANGELOG.md Normal file
View File

@ -0,0 +1,39 @@
# [0.1.0-develop.5](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.4...v0.1.0-develop.5) (2023-09-03)
### Bug Fixes
* need to slice out the key type byte ([578d965](https://git.lumeweb.com/LumeWeb/publish-webapp/commit/578d965550e3c381c9a92a2a61fee5b498353ee8))
# [0.1.0-develop.4](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.3...v0.1.0-develop.4) (2023-09-02)
### Bug Fixes
* only submit a new registry entry if the data has changed ([421cf81](https://git.lumeweb.com/LumeWeb/publish-webapp/commit/421cf81f362455b607373097a4173eda5780f060))
# [0.1.0-develop.3](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.2...v0.1.0-develop.3) (2023-09-02)
### Bug Fixes
* need to use the sre.pk not cidBytes ([232669e](https://git.lumeweb.com/LumeWeb/publish-webapp/commit/232669e7760a975017748f14d52b8f9a5cb13689))
# [0.1.0-develop.2](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.1.0-develop.1...v0.1.0-develop.2) (2023-09-02)
### Bug Fixes
* re-encode cid to be a webapp ([8e963d4](https://git.lumeweb.com/LumeWeb/publish-webapp/commit/8e963d4b0449dfcbeb55eae61c202cbfea5ffc9e))
### Features
* add support for creating a resolver CID for the app if APP_SEED is not false ([b03234e](https://git.lumeweb.com/LumeWeb/publish-webapp/commit/b03234e38e2bc8e1cd3cd21d8571fd809b768b5d))
# [0.1.0-develop.1](https://git.lumeweb.com/LumeWeb/publish-webapp/compare/v0.0.1...v0.1.0-develop.1) (2023-08-15)
### Features
* initial version ([5de6422](https://git.lumeweb.com/LumeWeb/publish-webapp/commit/5de6422a16ef9603c713951932019c8299436cb4))

18787
npm-shrinkwrap.json generated Normal file

File diff suppressed because it is too large Load Diff

42
package.json Normal file
View File

@ -0,0 +1,42 @@
{
"name": "@lumeweb/publish-webapp",
"version": "0.1.0-develop.5",
"type": "module",
"main": "lib/index.js",
"bin": "./lib/index.js",
"repository": {
"type": "git",
"url": "gitea@git.lumeweb.com:LumeWeb/publish-webapp.git"
},
"devDependencies": {
"@lumeweb/node-library-preset": "^0.2.7",
"@types/mime": "^3.0.1",
"@types/prompts": "^2.4.4",
"presetter": "*"
},
"readme": "ERROR: No README data found!",
"scripts": {
"prepare": "presetter bootstrap",
"build": "run build",
"semantic-release": "semantic-release"
},
"dependencies": {
"@lumeweb/libweb": "0.2.0-develop.39",
"@scure/bip39": "^1.2.1",
"array-from-async": "^3.0.0",
"chalk": "^5.3.0",
"ed25519-keygen": "^0.4.8",
"memory-level": "^1.0.0",
"mime": "^3.0.0",
"msgpackr": "^1.9.7",
"p-defer": "^4.0.0",
"p-queue": "^7.3.4",
"prompts": "^2.4.2"
},
"files": [
"lib"
],
"publishConfig": {
"access": "public"
}
}

244
src/index.ts Normal file
View File

@ -0,0 +1,244 @@
import { decodeCid, encodeCid } from "@lumeweb/libportal";
import {
BOOTSTRAP_NODES,
CID_HASH_TYPES,
CID_TYPES,
createKeyPair,
createNode,
REGISTRY_TYPES,
S5NodeConfig,
SignedRegistryEntry,
} from "@lumeweb/libs5";
import KeyPairEd25519 from "@lumeweb/libs5/lib/ed25519.js";
import fs from "fs/promises";
import { MemoryLevel } from "memory-level";
import { base58btc } from "multiformats/bases/base58";
import path from "path";
import * as process from "process";
import fromAsync from "array-from-async";
import * as util from "util";
import {
CID,
concatBytes,
equalBytes,
hexToBytes,
loginActivePortals,
maybeInitDefaultPortals,
setActivePortalMasterKey,
uploadObject,
} from "@lumeweb/libweb";
import chalk from "chalk";
import mime from "mime";
import { pack } from "msgpackr";
import PQueue from "p-queue";
import prompts from "prompts";
import * as bip39 from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english";
import { HDKey } from "ed25519-keygen/hdkey";
import defer from "p-defer";
import type { WebAppMetadata } from "#types.js";
const BIP44_PATH = "m/44'/1627'/0'/0'/0'";
let key = process.env.PORTAL_PRIVATE_KEY;
let dir = process.env.DIR;
const parallelUploads = parseInt(process.env.PARALLEL_UPLOADS ?? "0", 10) || 10;
if (!key) {
key = await prompts.prompts.password({
name: "private_key",
message: "Enter your private key",
validate: (prev: string) => prev && prev.length === 64,
type: undefined,
});
}
if (!dir) {
dir = (await prompts.prompts.text({
name: "dir",
message: "Enter the directory of the webapp",
validate: (prev: string) => prev && prev.length > 0,
type: undefined,
})) as unknown as string;
}
let seed = process.env.APP_SEED;
if (!seed && seed === undefined) {
// @ts-ignore
seed = await prompts.prompts.password({
name: "module_seed",
message: "Enter your app seed",
validate: (prev) => prev && bip39.validateMnemonic(prev, wordlist),
});
}
const hdKey = seed
? HDKey.fromMasterSeed(await bip39.mnemonicToSeed(seed as string)).derive(
BIP44_PATH,
)
: false;
dir = path.resolve(dir) + "/";
setActivePortalMasterKey(hexToBytes(key as string));
maybeInitDefaultPortals();
const processedFiles: Array<{ cid: string; file: string; size: number }> = [];
const queue = new PQueue({ concurrency: parallelUploads });
void (await loginActivePortals());
const files: string[] = await fromAsync(walkSync(dir));
files.forEach((item) => {
void queue.add(async () => processFile(item));
});
await queue.onIdle();
const metadata: WebAppMetadata = {
type: "web_app",
paths: {},
tryFiles: ["index.html"],
};
processedFiles
.sort((a, b) => {
if (a.file < b.file) {
return -1;
}
if (a.file > b.file) {
return 1;
}
return 0;
})
.forEach((item) => {
metadata.paths[item.file] = {
cid: item.cid,
contentType: mime.getType(item.file) ?? "application/octet-stream",
size: item.size,
};
});
const serializedMetadata = pack(metadata);
let [cid, err] = await uploadObject(serializedMetadata);
if (err) {
console.error("Failed to publish: ", err);
process.exit(1);
}
cid = decodeCid(cid) as CID;
cid = encodeCid(cid.hash, cid.size, CID_TYPES.METADATA_WEBAPP);
console.log(
util.format("%s: %s", chalk.green("Web App successfully published"), cid),
);
if (!hdKey) {
process.exit(0);
}
const db = new MemoryLevel<string, Uint8Array>({
storeEncoding: "view",
valueEncoding: "buffer",
});
await db.open();
let config = {
keyPair: createKeyPair(),
db,
p2p: {
peers: {
initial: [...BOOTSTRAP_NODES],
},
},
logger: {
info: (s: string) => {},
verbose: (s: string) => {},
warn: (s: string) => {},
error: (s: string) => {},
catched: (e: any, context?: string | null) => {},
},
} as S5NodeConfig;
const node = createNode(config);
await node.start();
const peerDefer = defer();
node.services.p2p.once("peerConnected", peerDefer.resolve);
await peerDefer.promise;
{
const cidBytes = decodeCid(cid);
const key = hdKey as HDKey;
let sre: SignedRegistryEntry;
let revision = 0;
const ret = await node.services.registry.get(
new KeyPairEd25519(key.privateKey).publicKey,
);
if (ret) {
revision = ret.revision + 1;
}
const newEntry = concatBytes(
Uint8Array.from([
REGISTRY_TYPES.CID,
CID_TYPES.RESOLVER,
CID_HASH_TYPES.BLAKE3,
]),
cidBytes.hash,
);
if (!equalBytes(ret?.data ?? new Uint8Array(), newEntry)) {
sre = node.services.registry.signRegistryEntry({
kp: new KeyPairEd25519((hdKey as HDKey).privateKey),
data: newEntry,
revision,
});
await node.services.registry.set(sre);
} else {
sre = ret as SignedRegistryEntry;
}
console.log(
util.format(
"%s: %s",
chalk.green("Resolver entry"),
encodeCid(sre.pk.slice(1), 0, CID_TYPES.RESOLVER, CID_HASH_TYPES.ED25519),
),
);
await node.stop();
}
async function processFile(filePath: string) {
const fd = await fs.open(filePath);
const size = (await fd.stat()).size;
const [cid, err] = await uploadObject(fd.createReadStream(), BigInt(size));
if (err) {
console.error("Failed to publish: ", err);
process.exit(1);
}
processedFiles.push({ cid, file: filePath.replace(dir as string, ""), size });
}
async function* walkSync(dir: string): AsyncGenerator<string> {
const files = await fs.readdir(dir, { withFileTypes: true });
for (const file of files) {
if (file.isDirectory()) {
yield* walkSync(path.join(dir, file.name));
} else {
yield path.join(dir, file.name);
}
}
}

23
src/types.ts Normal file
View File

@ -0,0 +1,23 @@
export interface WebAppMetadata {
type: "web_app";
name?: string;
tryFiles?: string[];
errorPages?: {
[key: string]: string; // key should match the pattern ^\d{3}$
};
paths: {
[path: string]: PathContent; // path has maxLength 255
};
extraMetadata?: ExtraMetadata; // I'm assuming this as any since the actual structure isn't provided
}
export interface PathContent {
cid: CID; // Assuming CID is another interface or type
contentType?: string; // Should match the provided pattern
size: number;
}
// Placeholder definitions based on the $ref in the schema.
// You should replace these with the actual structures if you have them.
export type CID = any;
export type ExtraMetadata = any;