mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feature/UI sideload (#2658)
* ui sideloading * remove subtlecrypto import * fix parser * misc fixes * allow docker pull during compat conversion
This commit is contained in:
@@ -2,9 +2,9 @@ import * as matches from "ts-matches"
|
||||
|
||||
const starSub = /((\d+\.)*\d+)\.\*/
|
||||
// prettier-ignore
|
||||
export type ValidEmVer = `${number}${`.${number}` | ""}${`.${number}` | ""}${`-${string}` | ""}`;
|
||||
export type ValidEmVer = string;
|
||||
// prettier-ignore
|
||||
export type ValidEmVerRange = `${'>=' | '<='| '<' | '>' | ''}${'^' | '~' | ''}${number | '*'}${`.${number | '*'}` | ""}${`.${number | '*'}` | ""}${`-${string}` | ""}`;
|
||||
export type ValidEmVerRange = string;
|
||||
|
||||
function incrementLastNumber(list: number[]) {
|
||||
const newList = [...list]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export { EmVer } from "./emverLite/mod"
|
||||
export { setupManifest } from "./manifest/setupManifest"
|
||||
export { setupExposeStore } from "./store/setupExposeStore"
|
||||
export { S9pk } from "./s9pk"
|
||||
export * as config from "./config"
|
||||
export * as CB from "./config/builder"
|
||||
export * as CT from "./config/configTypes"
|
||||
|
||||
@@ -6,6 +6,7 @@ export { setupManifest } from "./manifest/setupManifest"
|
||||
export { FileHelper } from "./util/fileHelper"
|
||||
export { setupExposeStore } from "./store/setupExposeStore"
|
||||
export { pathBuilder } from "./store/PathBuilder"
|
||||
export { S9pk } from "./s9pk"
|
||||
|
||||
export * as actions from "./actions"
|
||||
export * as backup from "./backup"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { PackageDetailLevel } from "./PackageDetailLevel"
|
||||
import type { PackageId } from "./PackageId"
|
||||
import type { Version } from "./Version"
|
||||
|
||||
export type GetPackageParams = {
|
||||
id: PackageId | null
|
||||
version: string | null
|
||||
sourceVersion: string | null
|
||||
sourceVersion: Version | null
|
||||
otherVersions: PackageDetailLevel | null
|
||||
}
|
||||
|
||||
@@ -28,6 +28,6 @@ export type Manifest = {
|
||||
dependencies: Dependencies
|
||||
hardwareRequirements: HardwareRequirements
|
||||
gitHash: string | null
|
||||
osVersion: Version
|
||||
osVersion: string
|
||||
hasConfig: boolean
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { Description } from "./Description"
|
||||
import type { HardwareRequirements } from "./HardwareRequirements"
|
||||
import type { MerkleArchiveCommitment } from "./MerkleArchiveCommitment"
|
||||
import type { RegistryAsset } from "./RegistryAsset"
|
||||
import type { Version } from "./Version"
|
||||
|
||||
export type PackageVersionInfo = {
|
||||
title: string
|
||||
@@ -17,7 +16,7 @@ export type PackageVersionInfo = {
|
||||
upstreamRepo: string
|
||||
supportSite: string
|
||||
marketingSite: string
|
||||
osVersion: Version
|
||||
osVersion: string
|
||||
hardwareRequirements: HardwareRequirements
|
||||
sourceVersion: string | null
|
||||
s9pk: RegistryAsset<MerkleArchiveCommitment>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { Governor } from "./Governor"
|
||||
import type { IpInfo } from "./IpInfo"
|
||||
import type { ServerStatus } from "./ServerStatus"
|
||||
import type { Version } from "./Version"
|
||||
import type { WifiInfo } from "./WifiInfo"
|
||||
|
||||
export type ServerInfo = {
|
||||
@@ -10,7 +9,7 @@ export type ServerInfo = {
|
||||
platform: string
|
||||
id: string
|
||||
hostname: string
|
||||
version: Version
|
||||
version: string
|
||||
lastBackup: string | null
|
||||
eosVersionCompat: string
|
||||
lanAddress: string
|
||||
|
||||
67
sdk/lib/s9pk/index.ts
Normal file
67
sdk/lib/s9pk/index.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { DataUrl, Manifest, MerkleArchiveCommitment } from "../osBindings"
|
||||
import { ArrayBufferReader, MerkleArchive } from "./merkleArchive"
|
||||
import mime from "mime"
|
||||
|
||||
const magicAndVersion = new Uint8Array([59, 59, 2])
|
||||
|
||||
export function compare(a: Uint8Array, b: Uint8Array) {
|
||||
if (a.length !== b.length) return false
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export class S9pk {
|
||||
private constructor(
|
||||
readonly manifest: Manifest,
|
||||
readonly archive: MerkleArchive,
|
||||
readonly size: number,
|
||||
) {}
|
||||
static async deserialize(
|
||||
source: Blob,
|
||||
commitment: MerkleArchiveCommitment | null,
|
||||
): Promise<S9pk> {
|
||||
const header = new ArrayBufferReader(
|
||||
await source
|
||||
.slice(0, magicAndVersion.length + MerkleArchive.headerSize)
|
||||
.arrayBuffer(),
|
||||
)
|
||||
const magicVersion = new Uint8Array(header.next(magicAndVersion.length))
|
||||
if (!compare(magicVersion, magicAndVersion)) {
|
||||
throw new Error("Invalid Magic or Unexpected Version")
|
||||
}
|
||||
|
||||
const archive = await MerkleArchive.deserialize(
|
||||
source,
|
||||
"s9pk",
|
||||
header,
|
||||
commitment,
|
||||
)
|
||||
|
||||
const manifest = JSON.parse(
|
||||
new TextDecoder().decode(
|
||||
await archive.contents
|
||||
.getPath(["manifest.json"])
|
||||
?.verifiedFileContents(),
|
||||
),
|
||||
)
|
||||
|
||||
return new S9pk(manifest, archive, source.length)
|
||||
}
|
||||
async icon(): Promise<DataUrl> {
|
||||
const iconName = Object.keys(this.archive.contents.contents).find(
|
||||
(name) =>
|
||||
name.startsWith("icon.") && mime.getType(name)?.startsWith("image/"),
|
||||
)
|
||||
if (!iconName) {
|
||||
throw new Error("no icon found in archive")
|
||||
}
|
||||
return (
|
||||
`data:${mime.getType(iconName)};base64,` +
|
||||
Buffer.from(
|
||||
await this.archive.contents.getPath([iconName])!.verifiedFileContents(),
|
||||
).toString("base64")
|
||||
)
|
||||
}
|
||||
}
|
||||
80
sdk/lib/s9pk/merkleArchive/directoryContents.ts
Normal file
80
sdk/lib/s9pk/merkleArchive/directoryContents.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { ArrayBufferReader, Entry } from "."
|
||||
import { blake3 } from "@noble/hashes/blake3"
|
||||
import { serializeVarint } from "./varint"
|
||||
import { FileContents } from "./fileContents"
|
||||
import { compare } from ".."
|
||||
|
||||
export class DirectoryContents {
|
||||
static readonly headerSize =
|
||||
8 + // position: u64 BE
|
||||
8 // size: u64 BE
|
||||
private constructor(readonly contents: { [name: string]: Entry }) {}
|
||||
static async deserialize(
|
||||
source: Blob,
|
||||
header: ArrayBufferReader,
|
||||
sighash: Uint8Array,
|
||||
maxSize: bigint,
|
||||
): Promise<DirectoryContents> {
|
||||
const position = header.nextU64()
|
||||
const size = header.nextU64()
|
||||
if (size > maxSize) {
|
||||
throw new Error("size is greater than signed")
|
||||
}
|
||||
|
||||
const tocReader = new ArrayBufferReader(
|
||||
await source
|
||||
.slice(Number(position), Number(position + size))
|
||||
.arrayBuffer(),
|
||||
)
|
||||
const len = tocReader.nextVarint()
|
||||
const entries: { [name: string]: Entry } = {}
|
||||
for (let i = 0; i < len; i++) {
|
||||
const name = tocReader.nextVarstring()
|
||||
const entry = await Entry.deserialize(source, tocReader)
|
||||
entries[name] = entry
|
||||
}
|
||||
|
||||
const res = new DirectoryContents(entries)
|
||||
|
||||
if (!compare(res.sighash(), sighash)) {
|
||||
throw new Error("hash sum does not match")
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
sighash(): Uint8Array {
|
||||
const hasher = blake3.create({})
|
||||
const names = Object.keys(this.contents).sort()
|
||||
hasher.update(new Uint8Array(serializeVarint(names.length)))
|
||||
for (const name of names) {
|
||||
const entry = this.contents[name]
|
||||
const nameBuf = new TextEncoder().encode(name)
|
||||
hasher.update(new Uint8Array(serializeVarint(nameBuf.length)))
|
||||
hasher.update(nameBuf)
|
||||
hasher.update(new Uint8Array(entry.hash))
|
||||
const sizeBuf = new Uint8Array(8)
|
||||
new DataView(sizeBuf.buffer).setBigUint64(0, entry.size)
|
||||
hasher.update(sizeBuf)
|
||||
hasher.update(new Uint8Array([0]))
|
||||
}
|
||||
|
||||
return hasher.digest()
|
||||
}
|
||||
getPath(path: string[]): Entry | null {
|
||||
if (path.length === 0) {
|
||||
return null
|
||||
}
|
||||
const next = this.contents[path[0]]
|
||||
const rest = path.slice(1)
|
||||
if (next === undefined) {
|
||||
return null
|
||||
}
|
||||
if (rest.length === 0) {
|
||||
return next
|
||||
}
|
||||
if (next.contents instanceof DirectoryContents) {
|
||||
return next.contents.getPath(rest)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
24
sdk/lib/s9pk/merkleArchive/fileContents.ts
Normal file
24
sdk/lib/s9pk/merkleArchive/fileContents.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { blake3 } from "@noble/hashes/blake3"
|
||||
import { ArrayBufferReader } from "."
|
||||
import { compare } from ".."
|
||||
|
||||
export class FileContents {
|
||||
private constructor(readonly contents: Blob) {}
|
||||
static deserialize(
|
||||
source: Blob,
|
||||
header: ArrayBufferReader,
|
||||
size: bigint,
|
||||
): FileContents {
|
||||
const position = header.nextU64()
|
||||
return new FileContents(
|
||||
source.slice(Number(position), Number(position + size)),
|
||||
)
|
||||
}
|
||||
async verified(hash: Uint8Array): Promise<ArrayBuffer> {
|
||||
const res = await this.contents.arrayBuffer()
|
||||
if (!compare(hash, blake3(new Uint8Array(res)))) {
|
||||
throw new Error("hash sum mismatch")
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
167
sdk/lib/s9pk/merkleArchive/index.ts
Normal file
167
sdk/lib/s9pk/merkleArchive/index.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { MerkleArchiveCommitment } from "../../osBindings"
|
||||
import { DirectoryContents } from "./directoryContents"
|
||||
import { FileContents } from "./fileContents"
|
||||
import { ed25519ph } from "@noble/curves/ed25519"
|
||||
import { sha512 } from "@noble/hashes/sha2"
|
||||
import { VarIntProcessor } from "./varint"
|
||||
import { compare } from ".."
|
||||
|
||||
const maxVarstringLen = 1024 * 1024
|
||||
|
||||
export type Signer = {
|
||||
pubkey: Uint8Array
|
||||
signature: Uint8Array
|
||||
maxSize: bigint
|
||||
context: string
|
||||
}
|
||||
|
||||
export class ArrayBufferReader {
|
||||
constructor(private buffer: ArrayBuffer) {}
|
||||
next(length: number): ArrayBuffer {
|
||||
const res = this.buffer.slice(0, length)
|
||||
this.buffer = this.buffer.slice(length)
|
||||
return res
|
||||
}
|
||||
nextU64(): bigint {
|
||||
return new DataView(this.next(8)).getBigUint64(0)
|
||||
}
|
||||
nextVarint(): number {
|
||||
const p = new VarIntProcessor()
|
||||
while (!p.finished()) {
|
||||
p.push(new Uint8Array(this.buffer.slice(0, 1))[0])
|
||||
this.buffer = this.buffer.slice(1)
|
||||
}
|
||||
const res = p.decode()
|
||||
if (res === null) {
|
||||
throw new Error("Reached EOF")
|
||||
}
|
||||
return res
|
||||
}
|
||||
nextVarstring(): string {
|
||||
const len = Math.min(this.nextVarint(), maxVarstringLen)
|
||||
return new TextDecoder().decode(this.next(len))
|
||||
}
|
||||
}
|
||||
|
||||
export class MerkleArchive {
|
||||
static readonly headerSize =
|
||||
32 + // pubkey
|
||||
64 + // signature
|
||||
32 + // sighash
|
||||
8 + // size
|
||||
DirectoryContents.headerSize
|
||||
private constructor(
|
||||
readonly signer: Signer,
|
||||
readonly contents: DirectoryContents,
|
||||
) {}
|
||||
static async deserialize(
|
||||
source: Blob,
|
||||
context: string,
|
||||
header: ArrayBufferReader,
|
||||
commitment: MerkleArchiveCommitment | null,
|
||||
): Promise<MerkleArchive> {
|
||||
const pubkey = new Uint8Array(header.next(32))
|
||||
const signature = new Uint8Array(header.next(64))
|
||||
const sighash = new Uint8Array(header.next(32))
|
||||
const rootMaxSizeBytes = header.next(8)
|
||||
const maxSize = new DataView(rootMaxSizeBytes).getBigUint64(0)
|
||||
|
||||
if (
|
||||
!ed25519ph.verify(
|
||||
signature,
|
||||
new Uint8Array(
|
||||
await new Blob([sighash, rootMaxSizeBytes]).arrayBuffer(),
|
||||
),
|
||||
pubkey,
|
||||
{
|
||||
context: new TextEncoder().encode(context),
|
||||
zip215: true,
|
||||
},
|
||||
)
|
||||
) {
|
||||
throw new Error("signature verification failed")
|
||||
}
|
||||
|
||||
if (commitment) {
|
||||
if (
|
||||
!compare(
|
||||
sighash,
|
||||
new Uint8Array(Buffer.from(commitment.rootSighash, "base64").buffer),
|
||||
)
|
||||
) {
|
||||
throw new Error("merkle root mismatch")
|
||||
}
|
||||
if (maxSize > commitment.rootMaxsize) {
|
||||
throw new Error("root directory max size too large")
|
||||
}
|
||||
} else if (maxSize > 1024 * 1024) {
|
||||
throw new Error(
|
||||
"root directory max size over 1MiB, cancelling download in case of DOS attack",
|
||||
)
|
||||
}
|
||||
|
||||
const contents = await DirectoryContents.deserialize(
|
||||
source,
|
||||
header,
|
||||
sighash,
|
||||
maxSize,
|
||||
)
|
||||
|
||||
return new MerkleArchive(
|
||||
{
|
||||
pubkey,
|
||||
signature,
|
||||
maxSize,
|
||||
context,
|
||||
},
|
||||
contents,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class Entry {
|
||||
private constructor(
|
||||
readonly hash: Uint8Array,
|
||||
readonly size: bigint,
|
||||
readonly contents: EntryContents,
|
||||
) {}
|
||||
static async deserialize(
|
||||
source: Blob,
|
||||
header: ArrayBufferReader,
|
||||
): Promise<Entry> {
|
||||
const hash = new Uint8Array(header.next(32))
|
||||
const size = header.nextU64()
|
||||
const contents = await deserializeEntryContents(source, header, hash, size)
|
||||
|
||||
return new Entry(new Uint8Array(hash), size, contents)
|
||||
}
|
||||
async verifiedFileContents(): Promise<ArrayBuffer> {
|
||||
if (!this.contents) {
|
||||
throw new Error("file is missing from archive")
|
||||
}
|
||||
if (!(this.contents instanceof FileContents)) {
|
||||
throw new Error("is not a regular file")
|
||||
}
|
||||
return this.contents.verified(this.hash)
|
||||
}
|
||||
}
|
||||
|
||||
export type EntryContents = null | FileContents | DirectoryContents
|
||||
async function deserializeEntryContents(
|
||||
source: Blob,
|
||||
header: ArrayBufferReader,
|
||||
hash: Uint8Array,
|
||||
size: bigint,
|
||||
): Promise<EntryContents> {
|
||||
const typeId = new Uint8Array(header.next(1))[0]
|
||||
switch (typeId) {
|
||||
case 0:
|
||||
return null
|
||||
case 1:
|
||||
return FileContents.deserialize(source, header, size)
|
||||
case 2:
|
||||
return DirectoryContents.deserialize(source, header, hash, size)
|
||||
default:
|
||||
throw new Error(`Unknown type id ${typeId} found in MerkleArchive`)
|
||||
}
|
||||
}
|
||||
62
sdk/lib/s9pk/merkleArchive/varint.ts
Normal file
62
sdk/lib/s9pk/merkleArchive/varint.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
const msb = 0x80
|
||||
const dropMsb = 0x7f
|
||||
const maxSize = Math.floor((8 * 8 + 7) / 7)
|
||||
|
||||
export class VarIntProcessor {
|
||||
private buf: Uint8Array
|
||||
private i: number
|
||||
constructor() {
|
||||
this.buf = new Uint8Array(maxSize)
|
||||
this.i = 0
|
||||
}
|
||||
push(b: number) {
|
||||
if (this.i >= maxSize) {
|
||||
throw new Error("Unterminated varint")
|
||||
}
|
||||
this.buf[this.i] = b
|
||||
this.i += 1
|
||||
}
|
||||
finished(): boolean {
|
||||
return this.i > 0 && (this.buf[this.i - 1] & msb) === 0
|
||||
}
|
||||
decode(): number | null {
|
||||
let result = 0
|
||||
let shift = 0
|
||||
let success = false
|
||||
for (let i = 0; i < this.i; i++) {
|
||||
const b = this.buf[i]
|
||||
const msbDropped = b & dropMsb
|
||||
result |= msbDropped << shift
|
||||
shift += 7
|
||||
|
||||
if ((b & msb) == 0 || shift > 9 * 7) {
|
||||
success = (b & msb) === 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
return result
|
||||
} else {
|
||||
console.error(this.buf)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function serializeVarint(int: number): ArrayBuffer {
|
||||
const buf = new Uint8Array(maxSize)
|
||||
let n = int
|
||||
let i = 0
|
||||
|
||||
while (n >= msb) {
|
||||
buf[i] = msb | n
|
||||
i += 1
|
||||
n >>= 7
|
||||
}
|
||||
|
||||
buf[i] = n
|
||||
i += 1
|
||||
|
||||
return buf.slice(0, i).buffer
|
||||
}
|
||||
@@ -8,18 +8,14 @@ describe("EmVer", () => {
|
||||
checker.check("1.2")
|
||||
checker.check("1.2.3")
|
||||
checker.check("1.2.3.4")
|
||||
// @ts-expect-error
|
||||
checker.check("1.2.3.4.5")
|
||||
// @ts-expect-error
|
||||
checker.check("1.2.3.4.5.6")
|
||||
expect(checker.check("1")).toEqual(true)
|
||||
expect(checker.check("1.2")).toEqual(true)
|
||||
expect(checker.check("1.2.3.4")).toEqual(true)
|
||||
})
|
||||
test("rangeOf('*') invalid", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => checker.check("a")).toThrow()
|
||||
// @ts-expect-error
|
||||
expect(() => checker.check("")).toThrow()
|
||||
expect(() => checker.check("1..3")).toThrow()
|
||||
})
|
||||
@@ -31,7 +27,6 @@ describe("EmVer", () => {
|
||||
expect(checker.check("2-beta123")).toEqual(true)
|
||||
expect(checker.check("2")).toEqual(true)
|
||||
expect(checker.check("1.2.3.5")).toEqual(true)
|
||||
// @ts-expect-error
|
||||
expect(checker.check("1.2.3.4.1")).toEqual(true)
|
||||
})
|
||||
|
||||
@@ -58,7 +53,6 @@ describe("EmVer", () => {
|
||||
test(`rangeOf(">=1.2.3.4") valid`, () => {
|
||||
expect(checker.check("2")).toEqual(true)
|
||||
expect(checker.check("1.2.3.5")).toEqual(true)
|
||||
// @ts-expect-error
|
||||
expect(checker.check("1.2.3.4.1")).toEqual(true)
|
||||
expect(checker.check("1.2.3.4")).toEqual(true)
|
||||
})
|
||||
@@ -73,7 +67,6 @@ describe("EmVer", () => {
|
||||
test(`rangeOf("<1.2.3.4") invalid`, () => {
|
||||
expect(checker.check("2")).toEqual(false)
|
||||
expect(checker.check("1.2.3.5")).toEqual(false)
|
||||
// @ts-expect-error
|
||||
expect(checker.check("1.2.3.4.1")).toEqual(false)
|
||||
expect(checker.check("1.2.3.4")).toEqual(false)
|
||||
})
|
||||
@@ -88,7 +81,6 @@ describe("EmVer", () => {
|
||||
test(`rangeOf("<=1.2.3.4") invalid`, () => {
|
||||
expect(checker.check("2")).toEqual(false)
|
||||
expect(checker.check("1.2.3.5")).toEqual(false)
|
||||
// @ts-expect-error
|
||||
expect(checker.check("1.2.3.4.1")).toEqual(false)
|
||||
})
|
||||
|
||||
@@ -196,7 +188,6 @@ describe("EmVer", () => {
|
||||
test(`rangeOf("!>1.2.3.4") invalid`, () => {
|
||||
expect(checker.check("2")).toEqual(false)
|
||||
expect(checker.check("1.2.3.5")).toEqual(false)
|
||||
// @ts-expect-error
|
||||
expect(checker.check("1.2.3.4.1")).toEqual(false)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as matches from "ts-matches"
|
||||
import * as YAML from "yaml"
|
||||
import * as TOML from "@iarna/toml"
|
||||
import _ from "lodash"
|
||||
import merge from "lodash.merge"
|
||||
import * as T from "../types"
|
||||
import * as fs from "node:fs/promises"
|
||||
|
||||
@@ -82,7 +82,7 @@ export class FileHelper<A> {
|
||||
|
||||
async merge(data: A, effects: T.Effects) {
|
||||
const fileData = (await this.read(effects).catch(() => ({}))) || {}
|
||||
const mergeData = _.merge({}, fileData, data)
|
||||
const mergeData = merge({}, fileData, data)
|
||||
return await this.write(mergeData, effects)
|
||||
}
|
||||
/**
|
||||
|
||||
84
sdk/package-lock.json
generated
84
sdk/package-lock.json
generated
@@ -1,29 +1,32 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-alpha1",
|
||||
"version": "0.3.6-alpha5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-alpha1",
|
||||
"version": "0.3.6-alpha5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@noble/curves": "^1.4.0",
|
||||
"@noble/hashes": "^1.4.0",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"ts-matches": "^5.4.1"
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mime": "^4.0.3",
|
||||
"ts-matches": "^5.5.1",
|
||||
"yaml": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/lodash.merge": "^4.6.2",
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-jest": "^29.0.5",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.0.4",
|
||||
"yaml": "^2.2.2"
|
||||
"typescript": "^5.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -653,8 +656,7 @@
|
||||
"node_modules/@iarna/toml": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
|
||||
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
@@ -1006,6 +1008,28 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz",
|
||||
"integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
"integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.25.24",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
|
||||
@@ -1144,6 +1168,15 @@
|
||||
"integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash.merge": {
|
||||
"version": "4.6.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz",
|
||||
"integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.15.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.10.tgz",
|
||||
@@ -2849,17 +2882,17 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
"integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
@@ -2918,6 +2951,20 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.3.tgz",
|
||||
"integrity": "sha512-KgUb15Oorc0NEKPbvfa0wRU+PItIEZmiv+pyAO2i0oTIVTJhlzMclU7w4RXWQrSOVH5ax/p/CkIO7KI4OyFJTQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
@@ -3580,9 +3627,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-matches": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-5.4.1.tgz",
|
||||
"integrity": "sha512-kXrY75F0s0WD15N2bWKDScKlKgwnusN6dTRzGs1N7LlxQRnazrsBISC1HL4sy2adsyk65Zbx3Ui3IGN8leAFOQ=="
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-5.5.1.tgz",
|
||||
"integrity": "sha512-UFYaKgfqlg9FROK7bdpYqFwG1CJvP4kOJdjXuWoqxo9jCmANoDw1GxkSCpJgoTeIiSTaTH5Qr1klSspb8c+ydg=="
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.1",
|
||||
@@ -4249,7 +4296,6 @@
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
|
||||
@@ -31,10 +31,13 @@
|
||||
"homepage": "https://github.com/Start9Labs/start-sdk#readme",
|
||||
"dependencies": {
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"ts-matches": "^5.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mime": "^4.0.3",
|
||||
"ts-matches": "^5.5.1",
|
||||
"yaml": "^2.2.2",
|
||||
"@iarna/toml": "^2.2.5"
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@noble/curves": "^1.4.0",
|
||||
"@noble/hashes": "^1.4.0"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "all",
|
||||
@@ -44,7 +47,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/lodash.merge": "^4.6.2",
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-jest": "^29.0.5",
|
||||
|
||||
Reference in New Issue
Block a user