✨ feat: [MAJOR] Rebrand (#101)
## Description **What issue are you solving (or what feature are you adding) and how are you doing it?** 1. Netris has been renamed and rebranded to Nestri. 2. New Logo and colors, plus a new Philosophy and mission(more on that later) 3. We are moving all different repos into this one - which means API, Docker, Website, Docs etc will be moved here
1
.github/CODEOWNERS
vendored
@@ -1 +0,0 @@
|
||||
* @wanjohiryan
|
||||
18
.github/dependabot.yml
vendored
@@ -1,18 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'gitsubmodule'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'type/build'
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
labels:
|
||||
- 'type/build'
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-patch"]
|
||||
119
.github/labeler.yml
vendored
@@ -1,119 +0,0 @@
|
||||
version: 2
|
||||
labels:
|
||||
- label: 'type/chore'
|
||||
branch: '^chore/.*'
|
||||
title: '^\s*.*?\schore(?:(.+))?!?:'
|
||||
|
||||
- label: 'type/fix'
|
||||
branch: '^fix/.*'
|
||||
title: '^\s*.*?\sfix(?:(.+))?!?:'
|
||||
|
||||
- label: 'type/feat'
|
||||
branch: '^feat/.*'
|
||||
title: '^\s*.*?\sfeat(?:(.+))?!?:'
|
||||
|
||||
- label: 'type/breaking'
|
||||
body: '(?i)breaking.*'
|
||||
|
||||
- label: 'type/docs'
|
||||
branch: '^docs/.*'
|
||||
title: '^\s*.*?\sdocs(?:(.+))?!?:'
|
||||
branch: '^docs/.*'
|
||||
files:
|
||||
- '**/*.md$'
|
||||
- '**/*.mdx$'
|
||||
|
||||
- label: 'type/ci'
|
||||
branch: '^ci/.*'
|
||||
title: '^\s*.*?\sci(?:(.+))?!?:'
|
||||
files:
|
||||
- '.github/.+'
|
||||
|
||||
- label: 'type/build'
|
||||
branch: '^dependabot/.*'
|
||||
title: '^\s*.*?\sbuild(?:(.+))?!?:'
|
||||
|
||||
- label: 'type/perf'
|
||||
title: '^\s*.*?\sperf(?:(.+))?!?:'
|
||||
|
||||
- label: 'mergeable/false'
|
||||
mergeable: False
|
||||
|
||||
- label: 'usr/dependabot'
|
||||
branch: '^dependabot/.*'
|
||||
authors:
|
||||
- 'dependabot[bot]'
|
||||
|
||||
- label: 'scope/back-end'
|
||||
files:
|
||||
- 'server.Dockerfile'
|
||||
|
||||
- label: 'scope/base'
|
||||
files:
|
||||
- 'base.Dockerfile'
|
||||
|
||||
- label: 'scope/ffmpeg'
|
||||
files:
|
||||
- 'ffmpeg.Dockerfile'
|
||||
|
||||
- label: 'scope/recorder'
|
||||
files:
|
||||
- 'recorder.Dockerfile'
|
||||
|
||||
- label: 'scope/relay'
|
||||
files:
|
||||
- 'relay.Dockerfile'
|
||||
|
||||
- label: 'scope/front-end'
|
||||
files:
|
||||
- 'apps/www/.+'
|
||||
|
||||
- label: 'pkg/www'
|
||||
files:
|
||||
- 'apps/www/.+'
|
||||
|
||||
- label: 'scope/git'
|
||||
files:
|
||||
- '**/.gitignore$'
|
||||
- '.github/.+'
|
||||
|
||||
- label: "size/xs"
|
||||
size:
|
||||
below: 10
|
||||
exclude-files: ["pnpm-lock.yml","yarn.lock"]
|
||||
|
||||
- label: "size/s"
|
||||
size:
|
||||
above: 9
|
||||
below: 100
|
||||
exclude-files: ["pnpm-lock.yml","yarn.lock"]
|
||||
|
||||
- label: "size/m"
|
||||
size:
|
||||
above: 49
|
||||
below: 200
|
||||
exclude-files: ["pnpm-lock.yml","yarn.lock"]
|
||||
|
||||
- label: "size/l"
|
||||
size:
|
||||
above: 199
|
||||
below: 500
|
||||
exclude-files: ["pnpm-lock.yml","yarn.lock"]
|
||||
|
||||
- label: "size/xl"
|
||||
size:
|
||||
above: 499
|
||||
below: 1000
|
||||
exclude-files: ["pnpm-lock.yml","yarn.lock"]
|
||||
|
||||
- label: "size/xxl"
|
||||
size:
|
||||
above: 999
|
||||
exclude-files: ["pnpm-lock.yml","yarn.lock"]
|
||||
|
||||
- label: "usr/wanjohi"
|
||||
authors: ['wanjohiryan']
|
||||
|
||||
- label: "usr/unknown"
|
||||
negate: True
|
||||
authors: ['wanjohiryan','apps/dependabot','dependabot', 'dependabot[bot]']
|
||||
108
.github/labels.yml
vendored
@@ -1,108 +0,0 @@
|
||||
# Default labels
|
||||
- name: "type/fix"
|
||||
color: "B60205"
|
||||
|
||||
- name: "type/build"
|
||||
color: "6C55D7"
|
||||
|
||||
- name: "type/feat"
|
||||
color: "0ADE12"
|
||||
|
||||
- name: "type/docs"
|
||||
color: "891059"
|
||||
|
||||
- name: "type/refactor"
|
||||
color: "8D44DF"
|
||||
|
||||
- name: "type/revert"
|
||||
color: "5319e7"
|
||||
|
||||
- name: "type/style"
|
||||
color: "D71964"
|
||||
|
||||
- name: "type/test"
|
||||
color: "0B9EE8"
|
||||
|
||||
- name: "type/breaking"
|
||||
color: "0590CC"
|
||||
|
||||
- name: "type/chore"
|
||||
color: "B44A63"
|
||||
|
||||
- name: "type/ci"
|
||||
color: "4FE1A6"
|
||||
|
||||
- name: "type/perf"
|
||||
color: "4FE1A6"
|
||||
|
||||
- name: "mergeable/false"
|
||||
color: "B60205"
|
||||
|
||||
- name: "priority/high"
|
||||
color: "D4E734"
|
||||
|
||||
- name: "priority/mid"
|
||||
color: "D4E734"
|
||||
|
||||
- name: "priority/low"
|
||||
color: "D4E734"
|
||||
|
||||
- name: "reg/docker"
|
||||
color: "5319e7"
|
||||
|
||||
- name: "reg/npm"
|
||||
color: "5319e7"
|
||||
|
||||
- name: "pkg/www"
|
||||
color: "5319e7"
|
||||
|
||||
- name: "pkg/lib"
|
||||
color: "5319e7"
|
||||
|
||||
- name: "pkg/aws"
|
||||
color: "5319e7"
|
||||
|
||||
- name: "scope/git"
|
||||
color: "B61B66"
|
||||
|
||||
- name: "scope/infra"
|
||||
color: "B61B66"
|
||||
|
||||
- name: "scope/front-end"
|
||||
color: "B61B66"
|
||||
|
||||
- name: "scope/relay"
|
||||
color: "B61B66"
|
||||
|
||||
- name: "scope/base"
|
||||
color: "B61B66"
|
||||
|
||||
- name: "scope/back-end"
|
||||
color: "B61B66"
|
||||
|
||||
- name: "size/xs"
|
||||
color: "AD4322"
|
||||
|
||||
- name: "size/s"
|
||||
color: "AD4322"
|
||||
|
||||
- name: "size/m"
|
||||
color: "AD4322"
|
||||
|
||||
- name: "size/l"
|
||||
color: "AD4322"
|
||||
|
||||
- name: "size/xl"
|
||||
color: "AD4322"
|
||||
|
||||
- name: "size/xxl"
|
||||
color: "AD4322"
|
||||
|
||||
- name: "usr/wanjohi"
|
||||
color: "09469C"
|
||||
|
||||
- name: "usr/dependabot"
|
||||
color: "09469C"
|
||||
|
||||
- name: "usr/unknown"
|
||||
color: "09469C"
|
||||
3
.github/pull_request_template.md
vendored
@@ -1,3 +0,0 @@
|
||||
## Description
|
||||
|
||||
**What issue are you solving (or what feature are you adding) and how are you doing it?**
|
||||
45
.github/release-drafter.yml
vendored
@@ -1,45 +0,0 @@
|
||||
name-template: 'v$RESOLVED_VERSION'
|
||||
tag-template: 'v$RESOLVED_VERSION'
|
||||
template: |
|
||||
# What's Changed
|
||||
|
||||
$CHANGES
|
||||
|
||||
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
|
||||
categories:
|
||||
- title: '⚠ Breaking Changes'
|
||||
label: 'type/breaking'
|
||||
- title: '🚀 New Features'
|
||||
label: 'type/feat'
|
||||
- title: '🐜 Bug Fixes'
|
||||
label: 'type/fix'
|
||||
- title: '🧰 Maintenance'
|
||||
label: 'type/chore'
|
||||
- title: '📖 Documentation'
|
||||
label: 'type/docs'
|
||||
- title: '⬆ Version Upgrades'
|
||||
label: 'type/build'
|
||||
collapse-after: 10
|
||||
- title: 'Other changes'
|
||||
collapse-after: 10
|
||||
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- 'type/breaking'
|
||||
minor:
|
||||
labels:
|
||||
- 'type/feat'
|
||||
patch:
|
||||
labels:
|
||||
- 'type/fix'
|
||||
- 'type/build'
|
||||
- 'type/docs'
|
||||
- 'type/chore'
|
||||
- 'type/refactor'
|
||||
- 'type/ci'
|
||||
- 'type/style'
|
||||
- 'type/test'
|
||||
|
||||
exclude-labels:
|
||||
- 'skip-changelog'
|
||||
93
.github/workflows/autolabeler.yml
vendored
@@ -1,93 +0,0 @@
|
||||
name: Pull request auto-labeller
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- labeled
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
- edited
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@cfb60706e18bc85e8aec535e3c577abe8f70378e
|
||||
id: lint_pr_title
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |-
|
||||
build
|
||||
chore
|
||||
ci
|
||||
deprecate
|
||||
docs
|
||||
feat
|
||||
fix
|
||||
perf
|
||||
refactor
|
||||
remove
|
||||
revert
|
||||
security
|
||||
style
|
||||
test
|
||||
requireScope: false
|
||||
# Ensures the subject start with an uppercase character.
|
||||
subjectPattern: ^([A-Z]).+$
|
||||
headerPattern: '^\s*.*?\s(\w*)(?:\(([\w$.\-*/ ]*)\))?: (.*)$'
|
||||
headerPatternCorrespondence: type, scope, subject
|
||||
subjectPatternError: |
|
||||
The subject "{subject}" found in the pull request title "{title}"
|
||||
didn't match the configured pattern. Please ensure that the subject
|
||||
starts with an uppercase character
|
||||
|
||||
- uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31
|
||||
# When the previous steps fails, the workflow would stop. By adding this
|
||||
# condition you can continue the execution with the populated error message.
|
||||
if: always() && (steps.lint_pr_title.outputs.error_message != null)
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
message: |
|
||||
Hey there and thank you for opening this pull request! 👋🏼
|
||||
|
||||
We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted.
|
||||
Additionally, the subject of the title must start with an uppercase character (e.g. feat: New `search` component).
|
||||
|
||||
```
|
||||
${{ steps.lint_pr_title.outputs.error_message }}
|
||||
```
|
||||
# Delete a previous comment when the issue has been resolved
|
||||
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
|
||||
uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
delete: true
|
||||
|
||||
label:
|
||||
needs: [ validate ]
|
||||
runs-on: ubuntu-latest
|
||||
name: Add labels
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
- name: Checkout your code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: srvaroa/labeler@v1
|
||||
with:
|
||||
config_path: .github/labeler.yml
|
||||
fail_on_error: true
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
135
.github/workflows/base.yml
vendored
@@ -1,135 +0,0 @@
|
||||
#Tabs not spaces, you moron :)
|
||||
|
||||
name: CI for netris:base
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "base.Dockerfile"
|
||||
- ".github/workflows/base.yml"
|
||||
schedule:
|
||||
- cron: 0 0 * * * # At the end of everyday
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "base.Dockerfile"
|
||||
- ".github/workflows/base.yml"
|
||||
tags:
|
||||
- v*.*.*
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: nestriness/nestri
|
||||
BASE_TAG_PREFIX: base
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
name: Build image on pr
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: base.Dockerfile
|
||||
context: ./
|
||||
push: false
|
||||
load: true
|
||||
tags: netris:base
|
||||
|
||||
build-docker-main:
|
||||
name: Build image on merge
|
||||
if: ${{github.ref == 'refs/heads/main'}}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: base.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: base.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
33
.github/workflows/labels.yml
vendored
@@ -1,33 +0,0 @@
|
||||
name: GH labels maintainer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
- '.github/workflows/labels.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
- '.github/workflows/labels.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Run Labeler
|
||||
uses: crazy-max/ghaction-github-labeler@v5
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GIT_MASTER_TOKEN }}"
|
||||
with:
|
||||
dry-run: ${{ github.event_name == 'pull_request' }}
|
||||
github-token: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
135
.github/workflows/relay.yml
vendored
@@ -1,135 +0,0 @@
|
||||
#Tabs not spaces, you moron :)
|
||||
|
||||
name: CI for netris:relay
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "relay.Dockerfile"
|
||||
- ".github/workflows/relay.yml"
|
||||
schedule:
|
||||
- cron: 0 0 * * * # At the end of everyday
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "relay.Dockerfile"
|
||||
- ".github/workflows/relay.yml"
|
||||
tags:
|
||||
- v*.*.*
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: netrisdotme/netris
|
||||
BASE_TAG_PREFIX: relay
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
name: Build image on pr
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: relay.Dockerfile
|
||||
context: ./
|
||||
push: false
|
||||
load: true
|
||||
tags: netris:relay
|
||||
|
||||
build-docker-main:
|
||||
name: Build image on merge
|
||||
if: ${{github.ref == 'refs/heads/main'}}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: relay.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: relay.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
16
.github/workflows/release-drafter.yml
vendored
@@ -1,16 +0,0 @@
|
||||
name: Release drafter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
update_release_draft:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
137
.github/workflows/server.yml
vendored
@@ -1,137 +0,0 @@
|
||||
#Tabs not spaces, you moron :)
|
||||
|
||||
name: CI for netris:server
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "server.Dockerfile"
|
||||
- ".scripts/**"
|
||||
- ".github/workflows/server.yml"
|
||||
schedule:
|
||||
- cron: 0 0 * * * # At the end of everyday
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "server.Dockerfile"
|
||||
- ".scripts/**"
|
||||
- ".github/workflows/server.yml"
|
||||
tags:
|
||||
- v*.*.*
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: nestriness/nestri
|
||||
BASE_TAG_PREFIX: server
|
||||
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
name: Build image on pr
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: server.Dockerfile
|
||||
context: ./
|
||||
push: false
|
||||
load: true
|
||||
tags: netris:server
|
||||
|
||||
build-docker-main:
|
||||
name: Build image on merge to main
|
||||
if: ${{github.ref == 'refs/heads/main'}}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: server.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: server.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
236
.github/workflows/warp-input.yml
vendored
@@ -1,236 +0,0 @@
|
||||
#Tabs not spaces, you moron :)
|
||||
|
||||
name: CI for netris:warp-input
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "warp-input.Dockerfile"
|
||||
- ".github/workflows/warp-input.yml"
|
||||
- "bin/input/**"
|
||||
schedule:
|
||||
- cron: 0 0 * * * # At the end of everyday
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "warp-input.Dockerfile"
|
||||
- ".github/workflows/warp-input.yml"
|
||||
- "bin/input/**"
|
||||
tags:
|
||||
- v*.*.*
|
||||
release:
|
||||
types: [published, created]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: nestriness/nestri
|
||||
BASE_TAG_PREFIX: warp-input
|
||||
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
name: Build image on pr
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: warp-input.Dockerfile
|
||||
context: ./
|
||||
push: false
|
||||
load: true
|
||||
tags: netris:warp-input
|
||||
|
||||
build-docker-main:
|
||||
name: Build image on merge to main
|
||||
if: ${{github.ref == 'refs/heads/main'}}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: warp-input.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: warp-input.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-warp-input-release:
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: bin/input
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: ubuntu-20.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
bundles: appimage
|
||||
asset_name: warp-input-ubuntu-amd64
|
||||
- host: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
bundles: msi
|
||||
asset_name: warp-input-windows-amd64
|
||||
# - host: macos-latest
|
||||
# target: x86_64-apple-darwin
|
||||
# bundles: dmg
|
||||
# asset_name: warp-input-macos-amd64
|
||||
# - host: macos-latest
|
||||
# target: aarch64-apple-darwin
|
||||
# bundles: dmg
|
||||
# asset_name: warp-input-macos-apple-silicon
|
||||
# - host: ubuntu-20.04
|
||||
# target: x86_64-unknown-linux-musl
|
||||
# - host: ubuntu-20.04
|
||||
# target: aarch64-unknown-linux-gnu
|
||||
# - host: ubuntu-20.04
|
||||
# target: aarch64-unknown-linux-musl
|
||||
# - host: ubuntu-20.04
|
||||
# target: armv7-unknown-linux-gnueabihf
|
||||
name: Build warp-input on release
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust
|
||||
id: toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.settings.target }}
|
||||
toolchain: stable
|
||||
components: clippy, rustfmt
|
||||
|
||||
- name: Cache Rust Dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: false
|
||||
prefix-key: 'v0-rust-deps'
|
||||
shared-key: ${{ matrix.settings.target }}
|
||||
|
||||
- name: Cargo build
|
||||
run: cargo build --target ${{ matrix.settings.target }} --release
|
||||
|
||||
- name: Copy and rename artifacts (Linux)
|
||||
if: ${{ matrix.settings.host == 'ubuntu-20.04' }}
|
||||
run: |
|
||||
cp target/${{ matrix.settings.target }}/release/warp-input ./warp-input
|
||||
|
||||
- name: Copy and rename artifacts (Windows)
|
||||
if: ${{ matrix.settings.host == 'windows-latest' }}
|
||||
run: |
|
||||
cp "target/${{ matrix.settings.target }}/release/warp-input.exe" ./warp-input.exe
|
||||
|
||||
- name: Copy and rename artifacts (macOS)
|
||||
if: ${{ matrix.settings.host == 'macos-latest' }}
|
||||
run: |
|
||||
cp target/${{ matrix.settings.target }}/release/warp-input ./warp-input
|
||||
|
||||
- name: Publish release for (${{ matrix.settings.host }})
|
||||
if: ${{ matrix.settings.host == 'windows-latest' }}
|
||||
uses: svenstaro/upload-release-action@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
file: ./bin/input/warp-input.exe
|
||||
asset_name: ${{ matrix.settings.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
|
||||
- name: Publish release for (${{ matrix.settings.host }})
|
||||
if: ${{ matrix.settings.host != 'windows-latest' }}
|
||||
uses: svenstaro/upload-release-action@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
file: ./bin/input/warp-input
|
||||
asset_name: ${{ matrix.settings.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
234
.github/workflows/warp.yml
vendored
@@ -1,234 +0,0 @@
|
||||
#Tabs not spaces, you moron :)
|
||||
|
||||
name: CI for netris:warp
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "warp.Dockerfile"
|
||||
- ".github/workflows/warp.yml"
|
||||
schedule:
|
||||
- cron: 0 0 * * * # At the end of everyday
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "warp.Dockerfile"
|
||||
- ".github/workflows/warp.yml"
|
||||
tags:
|
||||
- v*.*.*
|
||||
release:
|
||||
types: [published, created]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: nestriness/nestri
|
||||
BASE_TAG_PREFIX: warp
|
||||
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
name: Build image on pr
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: warp.Dockerfile
|
||||
context: ./
|
||||
push: false
|
||||
load: true
|
||||
tags: netris:warp
|
||||
|
||||
build-docker-main:
|
||||
name: Build image on merge to main
|
||||
if: ${{github.ref == 'refs/heads/main'}}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: warp.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: warp.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-warp-release:
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: moq-server
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: ubuntu-20.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
bundles: appimage
|
||||
asset_name: warp-ubuntu-amd64
|
||||
- host: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
bundles: msi
|
||||
asset_name: warp-windows-amd64
|
||||
- host: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
bundles: dmg
|
||||
asset_name: warp-macos-amd64
|
||||
- host: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
bundles: dmg
|
||||
asset_name: warp-macos-apple-silicon
|
||||
# - host: ubuntu-20.04
|
||||
# target: x86_64-unknown-linux-musl
|
||||
# - host: ubuntu-20.04
|
||||
# target: aarch64-unknown-linux-gnu
|
||||
# - host: ubuntu-20.04
|
||||
# target: aarch64-unknown-linux-musl
|
||||
# - host: ubuntu-20.04
|
||||
# target: armv7-unknown-linux-gnueabihf
|
||||
name: Build warp on release
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust
|
||||
id: toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.settings.target }}
|
||||
toolchain: stable
|
||||
components: clippy, rustfmt
|
||||
|
||||
- name: Cache Rust Dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: false
|
||||
prefix-key: 'v0-rust-deps'
|
||||
shared-key: ${{ matrix.settings.target }}
|
||||
|
||||
- name: Cargo build
|
||||
run: cargo build --target ${{ matrix.settings.target }} --manifest-path ./moq-pub/Cargo.toml --release
|
||||
|
||||
- name: Copy and rename artifacts (Linux)
|
||||
if: ${{ matrix.settings.host == 'ubuntu-20.04' }}
|
||||
run: |
|
||||
cp target/${{ matrix.settings.target }}/release/moq-pub ./warp
|
||||
|
||||
- name: Copy and rename artifacts (Windows)
|
||||
if: ${{ matrix.settings.host == 'windows-latest' }}
|
||||
run: |
|
||||
cp "target/${{ matrix.settings.target }}/release/moq-pub.exe" ./warp.exe
|
||||
|
||||
- name: Copy and rename artifacts (macOS)
|
||||
if: ${{ matrix.settings.host == 'macos-latest' }}
|
||||
run: |
|
||||
cp target/${{ matrix.settings.target }}/release/moq-pub ./warp
|
||||
|
||||
- name: Publish release for (${{ matrix.settings.host }})
|
||||
if: ${{ matrix.settings.host == 'windows-latest' }}
|
||||
uses: svenstaro/upload-release-action@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./moq-server/warp.exe
|
||||
asset_name: ${{ matrix.settings.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
|
||||
- name: Publish release for (${{ matrix.settings.host }})
|
||||
if: ${{ matrix.settings.host != 'windows-latest' }}
|
||||
uses: svenstaro/upload-release-action@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./moq-server/warp
|
||||
asset_name: ${{ matrix.settings.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
38
.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# Dependencies
|
||||
node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# Testing
|
||||
coverage
|
||||
|
||||
# Turbo
|
||||
.turbo
|
||||
|
||||
# Vercel
|
||||
.vercel
|
||||
|
||||
# Build Outputs
|
||||
.next/
|
||||
out/
|
||||
build
|
||||
dist
|
||||
|
||||
|
||||
# Debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "moq-server"]
|
||||
path = moq-server
|
||||
url = https://github.com/kixelated/moq-rs
|
||||
[submodule "cli"]
|
||||
path = cli
|
||||
url = https://github.com/nestriness/cli.git
|
||||
@@ -1,285 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
trap "echo TRAPed signal" HUP INT QUIT TERM
|
||||
|
||||
# Include our gpu helper functions
|
||||
source /etc/gpu_helpers.sh
|
||||
|
||||
# Create and modify permissions of XDG_RUNTIME_DIR
|
||||
sudo -u nestri mkdir -pm700 /tmp/runtime-1000
|
||||
sudo chown nestri:nestri /tmp/runtime-1000
|
||||
sudo -u nestri chmod 700 /tmp/runtime-1000
|
||||
# Make user directory owned by the user in case it is not
|
||||
sudo chown nestri:nestri /home/nestri || sudo chown nestri:nestri /home/nestri/* || { echo "$(date +"[%Y-%m-%d %H:%M:%S]") Failed to change user directory permissions. There may be permission issues."; }
|
||||
|
||||
#Input devices ownable by our default user
|
||||
export REQUIRED_DEVICES=${REQUIRED_DEVICES:-/dev/uinput /dev/input/event*}
|
||||
|
||||
declare -A group_map
|
||||
|
||||
for dev in $REQUIRED_DEVICES; do
|
||||
if [ -e "$dev" ]; then
|
||||
dev_group=$(stat -c "%G" "$dev")
|
||||
dev_gid=$(stat -c "%g" "$dev")
|
||||
|
||||
if [ "$dev_group" = "UNKNOWN" ]; then
|
||||
new_name="nestri-gid-$dev_gid"
|
||||
# We only have a GID for this group; create a named group for it
|
||||
# this isn't 100% necessary but it prevents some useless noise in the console
|
||||
sudo groupadd -g "$dev_gid" "$new_name"
|
||||
group_map[$new_name]=1
|
||||
else
|
||||
# the group already exists; just add it to the list
|
||||
group_map[$dev_group]=1
|
||||
fi
|
||||
|
||||
# is this device read/writable by the group? if not, make it so
|
||||
if [ "$(stat -c "%a" "$dev" | cut -c2)" -lt 6 ]; then
|
||||
sudo chmod g+rw "$dev"
|
||||
fi
|
||||
else
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Path '$dev' is not present."
|
||||
fi
|
||||
done
|
||||
|
||||
join_by() { local IFS="$1"; shift; echo "$*"; }
|
||||
|
||||
groups=$(join_by "," "${!group_map[@]}")
|
||||
if [ "$groups" != "" ]; then
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Adding user '${USER}' to groups: $groups"
|
||||
sudo usermod -a -G "$groups" "${USER}"
|
||||
else
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Not modifying user groups ($groups)"
|
||||
fi
|
||||
|
||||
# Remove directories to make sure the desktop environment starts
|
||||
sudo rm -rf /tmp/.X* ~/.cache
|
||||
# Change time zone from environment variable
|
||||
sudo ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | sudo tee /etc/timezone >/dev/null
|
||||
# Add gamescope directories to path
|
||||
export PATH="${PATH:+${PATH}:}/usr/local/games:/usr/games"
|
||||
|
||||
# This symbolic link enables running Xorg inside a container with `-sharevts`
|
||||
sudo ln -snf /dev/ptmx /dev/tty7
|
||||
# Start DBus without systemd
|
||||
sudo /etc/init.d/dbus start
|
||||
|
||||
# Install Proton-GE for this user
|
||||
nestri-proton -i
|
||||
|
||||
# Allow starting Xorg from a pseudoterminal instead of strictly on a tty console
|
||||
if [ ! -f "/etc/X11/Xwrapper.config" ]; then
|
||||
echo -e "allowed_users=anybody\nneeds_root_rights=yes" | sudo tee /etc/X11/Xwrapper.config > /dev/null
|
||||
fi
|
||||
if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
|
||||
sudo sed -i "s/allowed_users=console/allowed_users=anybody/;$ a needs_root_rights=yes" /etc/X11/Xwrapper.config
|
||||
fi
|
||||
|
||||
# Remove existing Xorg configuration
|
||||
if [ -f "/etc/X11/xorg.conf" ]; then
|
||||
sudo rm -f "/etc/X11/xorg.conf"
|
||||
fi
|
||||
|
||||
# Setting `VIDEO_PORT` to none disables RANDR/XRANDR, do not set this if using datacenter GPUs
|
||||
if [ "${VIDEO_PORT,,}" = "none" ]; then
|
||||
export CONNECTED_MONITOR="--use-display-device=None"
|
||||
# The X server is otherwise deliberately set to a specific video port despite not being plugged to enable RANDR/XRANDR, monitor will display the screen if plugged to the specific port
|
||||
else
|
||||
export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT}"
|
||||
fi
|
||||
|
||||
# A custom modeline should be generated because there is no monitor to fetch this information normally
|
||||
custom_modeline="$(cvt -r "${SIZEW}" "${SIZEH}" "${REFRESH}" | sed -n 2p)"
|
||||
custom_modeline_settings="$(echo "$custom_modeline" | sed 's/Modeline //')"
|
||||
custom_modeline_identifier="$(echo "$custom_modeline_settings" | awk '{print $1}' | tr -d '"')"
|
||||
|
||||
# Pre-populate GPU information manually
|
||||
if ! check_and_populate_gpus; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Select the GPU based on user input or first one available
|
||||
selected_gpu="${GPU_SELECTION,,:-}"
|
||||
if [[ -z "$selected_gpu" ]]; then
|
||||
selected_gpu="${gpu_map[0]}" # Select first available GPU
|
||||
echo "No GPU selected, using first one available: $selected_gpu"
|
||||
elif ! selected_gpu=$(check_selected_gpu "$selected_gpu"); then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Print selected GPU information
|
||||
echo "Selected GPU: $(print_gpu_info "$selected_gpu")"
|
||||
echo ""
|
||||
|
||||
# Get GPU vendor as separate variable
|
||||
selected_gpu_vendor=$(get_gpu_vendor "$selected_gpu")
|
||||
# Convert lshw gathered bus id into Xorg compatible one
|
||||
xorg_bus_id=$(get_gpu_bus_xorg "$selected_gpu")
|
||||
|
||||
# Get GPU card path if available
|
||||
selected_gpu_card=""
|
||||
gpu_screen_recorder_device_arg=""
|
||||
|
||||
card_result=$(get_gpu_card "$selected_gpu")
|
||||
if [[ $? -eq 0 && -n "$card_result" ]]; then
|
||||
selected_gpu_card="$card_result"
|
||||
gpu_screen_recorder_device_arg="-device $selected_gpu_card"
|
||||
fi
|
||||
|
||||
# Check if the selected GPU is an NVIDIA GPU
|
||||
if [[ "${selected_gpu_vendor,,}" =~ "nvidia" ]]; then
|
||||
echo "Selected GPU is NVIDIA. Handling NVIDIA-specific configuration..."
|
||||
|
||||
# Install NVIDIA userspace driver components including X graphic libraries
|
||||
if ! command -v nvidia-xconfig &> /dev/null; then
|
||||
# Driver version is provided by the kernel through the container toolkit
|
||||
export DRIVER_ARCH="$(dpkg --print-architecture | sed -e 's/arm64/aarch64/' -e 's/armhf/32bit-ARM/' -e 's/i.*86/x86/' -e 's/amd64/x86_64/' -e 's/unknown/x86_64/')"
|
||||
export DRIVER_VERSION="$(head -n1 </proc/driver/nvidia/version | awk '{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+\.[0-9\.]+/) {print $i; exit}}')"
|
||||
cd /tmp
|
||||
# If version is different, new installer will overwrite the existing components
|
||||
if [ ! -f "/tmp/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" ]; then
|
||||
# Check multiple sources in order to probe both consumer and datacenter driver versions
|
||||
curl -fsSL -O "https://international.download.nvidia.com/XFree86/Linux-${DRIVER_ARCH}/${DRIVER_VERSION}/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" || curl -fsSL -O "https://international.download.nvidia.com/tesla/${DRIVER_VERSION}/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" || { echo "Failed NVIDIA GPU driver download. Exiting."; exit 1; }
|
||||
fi
|
||||
# Extract installer before installing
|
||||
sudo sh "NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" -x
|
||||
cd "NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}"
|
||||
# Run installation without the kernel modules and host components
|
||||
sudo ./nvidia-installer --silent \
|
||||
--no-kernel-module \
|
||||
--install-compat32-libs \
|
||||
--no-nouveau-check \
|
||||
--no-nvidia-modprobe \
|
||||
--no-rpms \
|
||||
--no-backup \
|
||||
--no-check-for-alternate-installs
|
||||
sudo rm -rf /tmp/NVIDIA* && cd ~
|
||||
fi
|
||||
|
||||
# Generate /etc/X11/xorg.conf with nvidia-xconfig
|
||||
sudo nvidia-xconfig --virtual="${SIZEW}x${SIZEH}" --depth="$CDEPTH" --mode="$(echo "$custom_modeline" | awk '{print $2}' | tr -d '\"')" --allow-empty-initial-configuration --no-probe-all-gpus --busid="$xorg_bus_id" --include-implicit-metamodes --mode-debug --no-sli --no-base-mosaic --only-one-x-screen ${CONNECTED_MONITOR}
|
||||
# Guarantee that the X server starts without a monitor by adding more options to the configuration
|
||||
sudo sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck,NoEdidMaxPClkCheck,NoMaxSizeCheck,NoHorizSyncCheck,NoVertRefreshCheck,NoVirtualSizeCheck,NoExtendedGpuCapabilitiesCheck,NoTotalSizeCheck,NoDualLinkDVICheck,NoDisplayPortBandwidthCheck,AllowNon3DVisionModes,AllowNonHDMI3DModes,AllowNonEdidModes,NoEdidHDMI2Check,AllowDpInterlaced"' /etc/X11/xorg.conf
|
||||
|
||||
# Add custom generated modeline to the configuration
|
||||
sudo sed -i '/Section\s\+"Monitor"/a\ '"$custom_modeline" /etc/X11/xorg.conf
|
||||
# Prevent interference between GPUs, add this to the host or other containers running Xorg as well
|
||||
echo -e "Section \"ServerFlags\"\n Option \"AutoAddGPU\" \"false\"\nEndSection" | sudo tee -a /etc/X11/xorg.conf > /dev/null
|
||||
else
|
||||
echo "Selected GPU is non-NVIDIA. Handling common configuration..."
|
||||
|
||||
# We need permissions for the GPU(s)
|
||||
sudo chown -R root:root /dev/dri/*
|
||||
sudo chmod -R 777 /dev/dri/*
|
||||
|
||||
# Create common config file
|
||||
sudo touch /etc/X11/xorg.conf
|
||||
config_common_xorg="
|
||||
Section \"ServerLayout\"
|
||||
Identifier \"Layout0\"
|
||||
Screen 0 \"Screen0\"
|
||||
InputDevice \"Keyboard0\" \"CoreKeyboard\"
|
||||
InputDevice \"Mouse0\" \"CorePointer\"
|
||||
EndSection
|
||||
|
||||
Section \"InputDevice\"
|
||||
Identifier \"Mouse0\"
|
||||
Driver \"mouse\"
|
||||
Option \"Protocol\" \"auto\"
|
||||
Option \"Device\" \"/dev/mouse\"
|
||||
Option \"Emulate3Buttons\" \"no\"
|
||||
Option \"ZAxisMapping\" \"4 5\"
|
||||
EndSection
|
||||
|
||||
Section \"InputDevice\"
|
||||
Identifier \"Keyboard0\"
|
||||
Driver \"kbd\"
|
||||
EndSection
|
||||
|
||||
Section \"Device\"
|
||||
Identifier \"Device0\"
|
||||
Driver \"modesetting\"
|
||||
BusID \"$xorg_bus_id\"
|
||||
EndSection
|
||||
|
||||
Section \"Screen\"
|
||||
Identifier \"Screen0\"
|
||||
Device \"Device0\"
|
||||
Option \"ModeDebug\" \"True\"
|
||||
EndSection
|
||||
|
||||
Section \"ServerFLags\"
|
||||
Option \"AutoAddGPU\" \"off\"
|
||||
EndSection
|
||||
"
|
||||
echo "$config_common_xorg" | sudo tee /etc/X11/xorg.conf > /dev/null
|
||||
fi
|
||||
|
||||
# Default display is :0 across the container
|
||||
export DISPLAY=":0"
|
||||
# Run Xorg server with required extensions
|
||||
/usr/bin/Xorg vt7 -noreset -novtswitch -sharevts -dpi "${DPI}" -fakescreenfps "${REFRESH}" +extension "COMPOSITE" +extension "DAMAGE" +extension "GLX" +extension "RANDR" +extension "RENDER" +extension "MIT-SHM" +extension "XFIXES" +extension "XTEST" "${DISPLAY}" &
|
||||
|
||||
# Wait for X11 to start
|
||||
echo "Waiting for X socket"
|
||||
until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done
|
||||
echo "X socket is ready"
|
||||
|
||||
# Wait for X11 to start
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Waiting for X socket"
|
||||
until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") X socket is ready"
|
||||
|
||||
# Additional non-NVIDIA configuration required
|
||||
if [[ ! "${selected_gpu_vendor,,}" =~ "nvidia" ]]; then
|
||||
# Get a list of all available outputs (connected or disconnected)
|
||||
all_outputs=($(xrandr --query | awk '/ connected| disconnected/ {print $1}'))
|
||||
|
||||
for selected_output in "${all_outputs[@]}"; do
|
||||
# Create a unique mode identifier by appending the output name
|
||||
unique_mode_identifier="${selected_output}-${custom_modeline_identifier}"
|
||||
|
||||
# Create a unique modeline setting with the new identifier
|
||||
unique_modeline_settings="$(echo "$custom_modeline_settings" | sed "s/$custom_modeline_identifier/$unique_mode_identifier/" | tr -d '"')"
|
||||
|
||||
# Check if the mode already exists for this output (avoid duplicates)
|
||||
if xrandr --query | grep "$selected_output" | grep -q "$unique_mode_identifier"; then
|
||||
echo "Mode '$unique_mode_identifier' already exists for output '$selected_output', skipping.."
|
||||
continue
|
||||
fi
|
||||
|
||||
# Add the new mode for the specific output (using the unique settings variable)
|
||||
if xrandr --newmode $unique_modeline_settings; then
|
||||
echo "Successfully added mode '$unique_mode_identifier' for output '$selected_output'"
|
||||
|
||||
# Configure the output to use the new mode
|
||||
if xrandr --addmode "$selected_output" "$unique_mode_identifier" && \
|
||||
xrandr --output "$selected_output" --primary --mode "$unique_mode_identifier"; then
|
||||
echo "Successfully configured output '$selected_output' to use mode '$unique_mode_identifier'"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Failed to configure output '$selected_output' to use mode '$unique_mode_identifier', trying the next output.."
|
||||
done
|
||||
|
||||
if [[ "$selected_output" == "${all_outputs[-1]}" ]]; then
|
||||
echo "Could not configure any output with the desired mode"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make sure gpu-screen-recorder is owned by nestri
|
||||
sudo chown nestri:nestri /usr/bin/gpu-screen-recorder
|
||||
|
||||
if [[ -z "${SESSION_ID}" ]]; then
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") No stream name was found, did you forget to set the env variable NAME?" && exit 1
|
||||
else
|
||||
/usr/bin/gpu-screen-recorder $gpu_screen_recorder_device_arg -v no -w screen -c flv -f "${REFRESH}" -a "$(pactl get-default-sink).monitor" | ffmpeg -hide_banner -v quiet -i pipe:0 -c copy -f mp4 -movflags empty_moov+frag_every_frame+separate_moof+omit_tfhd_offset - | /usr/bin/warp --name "${SESSION_ID}" https://fst.so:4443 &
|
||||
fi
|
||||
|
||||
openbox-session &
|
||||
|
||||
# /usr/games/gamescope -- mangohud glxgears > /dev/null &
|
||||
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Session Running. Press [Return] to exit."
|
||||
read
|
||||
610
.scripts/proton
@@ -1,610 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Version 1.1
|
||||
#Copied from https://github.com/noabody/unibuild/blob/master/data/wstart
|
||||
|
||||
# WINEARCH win32/win64 not as good as binary wine/wine64"
|
||||
# WINEDEBUG="-all" not as good as dev/null
|
||||
|
||||
# complex command line builder to simplify command objects
|
||||
# vars bin, pfx set to wine binary, prefix dirs initially
|
||||
# menus will dynamically set bin pfx to specific targets
|
||||
# menu shows gui based 32/64-bit pe header exe via pev
|
||||
# var 'x' for unified cross-functionality
|
||||
# ${@:2} skips 'wstart' and 1st arg
|
||||
|
||||
# manjaro 21.2.1
|
||||
#sudo pacman -S bash binutils findutils gendesk grep icoutils pcre2 perl yay winetricks; yay -S pev
|
||||
|
||||
# wnbin needs wine dir with: bin lib lib64 share
|
||||
# manjaro default path is /usr
|
||||
# can symlink various wnbin="$HOME/.local/opt"
|
||||
#mkdir "$HOME"/.local/opt
|
||||
#ln -sf /usr "$HOME"/.local/opt/wine
|
||||
#ln -sf /usr/share/steam/compatibilitytools.d/proton-ge-custom/files "$HOME"/.local/opt/proton
|
||||
|
||||
wnbin="/usr"
|
||||
# top level wine dir, symlink into "$HOME/.local/opt" to flatten paths
|
||||
wnpfx="$HOME"
|
||||
# top level wine prefix dir
|
||||
pntop="$HOME/.steam"
|
||||
# top level linux steam dir
|
||||
pnapp="$pntop/steam/steamapps"
|
||||
# steamapps subdir
|
||||
pnbin="$pnapp/common"
|
||||
# proton subdir normally under top/app
|
||||
pnpfx="$pnapp/compatdata"
|
||||
# proton prefix subdir normally under top/app
|
||||
pnpge="$pntop/root/compatibilitytools.d"
|
||||
# proton ge
|
||||
progs="drive_c/Program Files"
|
||||
# Program Files standard subdir
|
||||
stcmn="Steam/steamapps/common"
|
||||
# windows steam client subdir under progs
|
||||
desk="$HOME/Desktop"
|
||||
# desktop entry folder
|
||||
icon="applications-other"
|
||||
# default icon
|
||||
temp="$HOME/Downloads"
|
||||
# temp folder
|
||||
clprm=("${@:2}")
|
||||
# store cmdline args minus first option
|
||||
x="$(echo "$1" | grep -Pio '(?<=-)[wp]')"
|
||||
# 1st letter of 1st cmd line arg determines wine/proton
|
||||
if [[ -n "$x" ]]; then
|
||||
xarg="$(echo "$1" | perl -pe 's/-[wp]/-x/gi')"
|
||||
else
|
||||
xarg="$(echo "$1" | perl -pe 's/-x+/-/gi')"
|
||||
fi
|
||||
# drop 1st letter x or change to it
|
||||
xcmd=()
|
||||
i_mnus=()
|
||||
myprnt=()
|
||||
i_syms=()
|
||||
pmenu=("Command Prompt/wineconsole.exe" "Control Panel/control.exe" "Registry Editor/regedit.exe" "Task Manager/taskmgr.exe" "Windows Explorer/explorer.exe" "Wine Configuration/winecfg.exe")
|
||||
# scalable built-in programs menu
|
||||
unset WINEARCH WINEDLLPATH WINEPREFIX STEAM_COMPAT_CLIENT_INSTALL_PATH STEAM_COMPAT_DATA_PATH
|
||||
# prevent shell inheritance of env vars we use
|
||||
|
||||
w_menu () {
|
||||
PS3="Please enter your choice: "
|
||||
select answer in "${i_mnus[@]}"; do
|
||||
for item in "${i_mnus[@]}"; do
|
||||
if [[ $item == "$answer" ]]; then
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
# repeating menu requires valid selection from array
|
||||
if [[ "$answer" = "quit" ]]; then
|
||||
# pop quit from end of array for menu option
|
||||
exit
|
||||
else
|
||||
xmrtn="$answer"
|
||||
fi
|
||||
unset i_mnus
|
||||
clear
|
||||
}
|
||||
|
||||
# Path ordering: wine64 x64/x32 or wine32 x32 then standard
|
||||
# Order critical to proper operation
|
||||
xn64 () {
|
||||
xstrt="wine64"
|
||||
xnldl="$xnbin/lib64:$xnbin/lib"
|
||||
xndll="$xnbin/lib64/wine:$xnbin/lib/wine"
|
||||
}
|
||||
|
||||
xn32 () {
|
||||
xstrt="wine"
|
||||
xnldl="$xnbin/lib"
|
||||
xndll="$xnbin/lib/wine"
|
||||
}
|
||||
|
||||
xnint () {
|
||||
if [[ "$x" = "p" ]]; then
|
||||
xnbin="$pnbin"
|
||||
xnpfx="$pnpfx"
|
||||
dpth=(4 3)
|
||||
else
|
||||
xnbin="$wnbin"
|
||||
xnpfx="$wnpfx"
|
||||
dpth=(3 2)
|
||||
fi
|
||||
}
|
||||
|
||||
xnexe () {
|
||||
# menu installed wine/proton or exit
|
||||
readarray -t i_mnus < <(find -L "$xnbin" -maxdepth "${dpth[0]}" -type f -iname 'wine' ! \( -ipath '*/sbin*' \) 2>/dev/null | perl -pe "s|\Q$xnbin\E/(.*)[/]*bin/wine|\1| ; s|/$||" | sort ; echo "quit")
|
||||
if [[ ${#i_mnus[@]} -gt 2 ]]; then
|
||||
clear
|
||||
w_menu
|
||||
xnbin="$(realpath "$xnbin/$xmrtn")"
|
||||
unset xmrtn
|
||||
elif [[ ${#i_mnus[@]} -eq 2 ]]; then
|
||||
xnbin="$(realpath "$xnbin/${i_mnus[0]}")"
|
||||
else
|
||||
echo "No installed Wine/Proton found."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
xndef () {
|
||||
# create default prefix cross-function
|
||||
if [[ "$x" = "p" ]]; then
|
||||
if [[ ! -d "$xnpfx/0" ]]; then
|
||||
# always create default 0 prefix
|
||||
xnpfx="$xnpfx/0"
|
||||
echo "Creating default prefix: $xnpfx"
|
||||
mkdir -p "$xnpfx"
|
||||
STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run > /dev/null 2>&1 &
|
||||
xnpfx="$xnpfx/pfx"
|
||||
fi
|
||||
else
|
||||
if [[ ! -d "$xnpfx/.wine" ]]; then
|
||||
# always create default wine prefix
|
||||
xnpfx="$xnpfx/.wine"
|
||||
echo "Creating default prefix: $xnpfx"
|
||||
WINEPREFIX="$xnpfx" "$xnbin"/bin/winecfg > /dev/null 2>&1 &
|
||||
if [[ -d "$HOME/.wine" && "$HOME/.wine" != "$xnpfx" ]]; then
|
||||
rm -rf "$HOME"/.wine
|
||||
ln -sf "$xnpfx" "$HOME"/.wine
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
xnpre () {
|
||||
# menu wine/proton prefix
|
||||
readarray -t i_mnus < <(find "$xnpfx" -maxdepth "${dpth[1]}" -type f -iname 'system.reg' 2>/dev/null | perl -pe "s|\Q$xnpfx\E/(.*)/system.reg|\1|" | sort ; echo "quit")
|
||||
# use perl escaped Q/E to preserve special characters in path variable
|
||||
if [[ ${#i_mnus[@]} -gt 2 ]]; then
|
||||
# display menu with min two options plus quit
|
||||
# guard proton cross-function
|
||||
if [[ "$x" = "p" ]]; then
|
||||
# shellcheck disable=SC2044
|
||||
for value in $(find "$xnpfx" -maxdepth 1 -type d -ipath '*/[0-9]*' -printf "${xnpfx///compatdata}/appmanifest_%P.acf\n" 2>/dev/null); do
|
||||
test -f "$value" && myprnt+=("$(grep -Pio '^\s+\"(appid|name)\"\s+\"(.*)\"' "$value" | perl -pe 's/.*appid.+?\"(.*)\"\v|.*name.+?\"(.*)\"/\1 \2/')")
|
||||
done
|
||||
if [[ ${#myprnt[@]} -gt 0 ]]; then
|
||||
printf '%s\n' "${myprnt[@]}" | sort
|
||||
fi
|
||||
# correlate appmanifest to proton prefix and list before menu
|
||||
unset myprnt
|
||||
fi
|
||||
w_menu
|
||||
xnpfx="$xnpfx/$xmrtn"
|
||||
unset xmrtn
|
||||
elif [[ ${#i_mnus[@]} -eq 2 ]]; then
|
||||
# don't menu if only one option plus quit
|
||||
xnpfx="$xnpfx/${i_mnus[0]}"
|
||||
fi
|
||||
if [[ -d "$xnpfx/$progs (x86)" ]]; then
|
||||
xn64
|
||||
else
|
||||
xn32
|
||||
fi
|
||||
}
|
||||
|
||||
xnenv () {
|
||||
# core env vars allow proper targetting of wine/proton
|
||||
xpath="$xnbin/bin:$PATH"
|
||||
xcmd=(env PATH="$xpath" WINEDLLPATH="$xndll" LD_LIBRARY_PATH="$xnldl" WINEPREFIX="$xnpfx")
|
||||
# guard proton cross-function which adds on to core env vars
|
||||
if [[ "$x" = "p" ]]; then
|
||||
xcmd+=(STEAM_COMPAT_DATA_PATH="${xnpfx///pfx}" STEAM_COMPAT_CLIENT_INSTALL_PATH="$pntop")
|
||||
fi
|
||||
}
|
||||
|
||||
xnldr () {
|
||||
# loader default to proton as applicable, otherwise wine
|
||||
if [[ "$x" = "p" ]]; then
|
||||
read -r -p 'wine loader? [y/N] ' chse
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xcmd+=("$xstrt")
|
||||
else
|
||||
xcmd+=("${xnbin%/*}/proton" "run")
|
||||
fi
|
||||
else
|
||||
xcmd+=("$xstrt")
|
||||
fi
|
||||
}
|
||||
|
||||
xnset () {
|
||||
# set cross-fuction
|
||||
xnint
|
||||
# wine/proton menu
|
||||
xnexe
|
||||
# create default prefix as required
|
||||
xndef
|
||||
# wine/proton prefix
|
||||
xnpre
|
||||
# wine/proton env vars
|
||||
xnenv
|
||||
}
|
||||
|
||||
xlnch () {
|
||||
# cross-function command line launcher
|
||||
if [[ -z "$dbg" ]]; then
|
||||
("${xcmd[@]}" > /dev/null 2>&1 &)
|
||||
else
|
||||
echo "${xcmd[@]}"
|
||||
if [[ "$dbg" = "1" ]]; then
|
||||
("${xcmd[@]}" &)
|
||||
elif [[ "$dbg" = "2" ]]; then
|
||||
(WINEDEBUG="warn+all" "${xcmd[@]}" &)
|
||||
fi
|
||||
fi
|
||||
# prepend cmd with dbg=1 to see command and default debug output
|
||||
# dbg=2 to see command and all debug output, dbg=? for command only
|
||||
}
|
||||
|
||||
allexe () {
|
||||
# unfiltered list of exe in specified path
|
||||
if [[ -n "$(stat --file-system --format=%T "$(stat --format=%m "$pedir" 2>/dev/null)" 2>/dev/null | grep -Pio 'fuse')" ]]; then
|
||||
readarray -t i_mnus < <(find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit")
|
||||
# skip exe validity tests if file is on network drive
|
||||
else
|
||||
readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort ; echo "quit")
|
||||
# perform exe validity tests if file is on local drive
|
||||
fi
|
||||
}
|
||||
|
||||
fewexe () {
|
||||
# filtered list of exe in standard paths
|
||||
readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort ; echo "quit")
|
||||
# valid exe will have gui and icon
|
||||
}
|
||||
|
||||
alloth () {
|
||||
# unfiltered list of variable type in specified path
|
||||
readarray -t i_mnus < <(find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit")
|
||||
}
|
||||
|
||||
fewoth () {
|
||||
# filtered list of variable type in standard paths
|
||||
readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit")
|
||||
}
|
||||
|
||||
xbld () {
|
||||
# cross-function custom prefix builder
|
||||
pnpfx="$pnpfx/${clprm[0]}"
|
||||
wnpfx="$wnpfx/${clprm[0]}"
|
||||
xnint
|
||||
if [[ -z "${clprm[0]}" ]]; then
|
||||
echo "Wine/Proton prefix name required: (e.g. .wine, 0 )"
|
||||
elif [[ -d "$xnpfx" ]]; then
|
||||
echo "Wine/Proton Prefix exists: $xnpfx"
|
||||
else
|
||||
xnexe
|
||||
echo "Creating Wine/Proton Prefix: ${clprm[0]}"
|
||||
if [[ "$x" = "p" ]]; then
|
||||
xnenv
|
||||
mkdir -p "$xnpfx"
|
||||
xcmd+=(STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" "run")
|
||||
else
|
||||
read -r -p '32-bit only? [y/N] ' chse
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xn32
|
||||
xnenv
|
||||
xcmd+=(WINEARCH="win32" "$xstrt" "winecfg.exe")
|
||||
else
|
||||
xn64
|
||||
xnenv
|
||||
xcmd+=(WINEARCH="win64" "$xstrt" "winecfg.exe")
|
||||
fi
|
||||
fi
|
||||
xlnch
|
||||
fi
|
||||
}
|
||||
|
||||
xpmn () {
|
||||
# use specified exe, menu specified folder, or menu system
|
||||
if [[ -f "${clprm[0]}" ]]; then
|
||||
# parse 1st cmdline arg, queue if valid file
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
xmrtn="$(basename "$pedir")"
|
||||
pedir="$(dirname "$pedir")"
|
||||
else
|
||||
if [[ -d "${clprm[0]}" ]]; then
|
||||
# parse 1st cmdline arg, use as path if valid
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
test -z "$xflt" && allexe || alloth
|
||||
else
|
||||
# if no cmdline path, use prefix drive_c
|
||||
pedir="$xnpfx/drive_c"
|
||||
test -z "$xflt" && fewexe || fewoth
|
||||
fi
|
||||
# create menu, from path, of file
|
||||
test ${#i_mnus[@]} -gt 1 && w_menu
|
||||
fi
|
||||
}
|
||||
|
||||
xlyt() {
|
||||
# pe layout for launch
|
||||
# 64-bit prefix, 32-bit pe header, reset env to 32
|
||||
if [[ -n "$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Pi 'magic number.*0x10b')" && -d "$xnpfx/$progs (x86)" ]]; then
|
||||
xn32
|
||||
xnenv
|
||||
fi
|
||||
xnldr
|
||||
# if 1st arg is file/folder, skip it and run selection + remaining args
|
||||
if [[ -e "${clprm[0]}" ]];then
|
||||
xcmd+=("$pedir/$xmrtn" "${clprm[@]:1}")
|
||||
else
|
||||
xcmd+=("$pedir/$xmrtn" "${clprm[@]}")
|
||||
fi
|
||||
}
|
||||
|
||||
xstm() {
|
||||
if [[ "$x" = "p" ]]; then
|
||||
sstrt="$(realpath "$(which steam)" 2>/dev/null)"
|
||||
else
|
||||
xnset
|
||||
sstrt="$(find "$xnpfx/drive_c" -maxdepth 3 -iname 'steam.exe' 2>/dev/null)"
|
||||
if [[ -f "$sstrt" ]]; then
|
||||
pnapp="$(dirname "$sstrt")/steamapps"
|
||||
xcmd+=("$xstrt")
|
||||
fi
|
||||
fi
|
||||
# find wine/proton steam binary path, normally subdir of program files
|
||||
if [[ -f "$sstrt" ]]; then
|
||||
test -d "$pnapp" && readarray -t i_mnus < <(find "$pnapp" -maxdepth 1 -type f -iname 'appmanifest_*.acf' -exec grep -Pio '^\s+\"(appid|name)\"\s+\"(.*)\"' "{}" \; 2>/dev/null | perl -pe 's/.*appid.+?\"(.*)\"\v|.*name.+?\"(.*)\"/\1 \2/' | sort ; echo -e "steam\nquit")
|
||||
# read appmanifests to create menu entries
|
||||
test ${#i_mnus[@]} -gt 2 && w_menu && xmrtn="$(expr "$xmrtn" : '\([0-9]*\)')"
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
# lauch selection with steam
|
||||
xcmd+=("$sstrt" "-no-browser" "-applaunch" "$xmrtn")
|
||||
xlnch
|
||||
else
|
||||
# launch steam was selected
|
||||
# minigamelist (short game list) for no-browser (disabled chrome) to save memory
|
||||
xcmd+=("$sstrt" "-no-browser" "steam://open/minigameslist")
|
||||
xlnch
|
||||
fi
|
||||
else
|
||||
echo -e "Steam not found."
|
||||
fi
|
||||
}
|
||||
|
||||
xpge () {
|
||||
test -d "$pnpge" || mkdir -p "$pnpge"
|
||||
test -d "$pnbin" || mkdir -p "$pnbin"
|
||||
|
||||
if [[ ! -d "$(dirname "$pnpge")" ]]; then
|
||||
echo -e "Could not create folder 'compatibilitytools.d/protonge' in:\n $(dirname "$pnpge")\n because that path does not exist.\nVerify script variable 'pnpge'"
|
||||
elif [[ ! -d "$pnbin" ]]; then
|
||||
echo -e "Could not create sym-link 'protonge' in:\n $pnbin\n because that path does not exist.\nVerify script variable 'pnbin'"
|
||||
else
|
||||
gedl="$(curl -sL https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | jq -r ".tag_name")"
|
||||
# gedl="$(gh release list -R GloriousEggroll/proton-ge-custom -L 1 | grep -Pio '^ge[^ ]+')"
|
||||
gever="$(echo "$gedl" | grep -Pio '(?<=ge-proton).*')"
|
||||
if [[ -f "$pnpge/protonge/version" ]]; then
|
||||
if [[ -z "$(grep -Pio "$gever" "$pnpge/protonge/version")" ]]; then
|
||||
echo -e "Available Proton GE $gever differs from installed, updating...\n"
|
||||
chse=y
|
||||
else
|
||||
echo -e "Available Proton GE $gever matches installed, nothing to do.\n"
|
||||
fi
|
||||
else
|
||||
echo -e "Proton GE not found, installing...\n"
|
||||
chse=y
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$chse" ]]; then
|
||||
wget --progress=dot:giga "$(curl -s https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | grep browser_download_url | cut -d\" -f4 | grep .tar.gz)" -P "$temp"/
|
||||
|
||||
rm -rf "$pnpge/protonge"
|
||||
tar -xf "$temp/$gedl".tar.gz -C "$pnpge/"
|
||||
mv "$pnpge"/*roton* "$pnpge/protonge"
|
||||
rm -f "$temp/$gedl".tar.gz
|
||||
grep -Piq "$gever" "$pnpge/protonge/version" || perl -pi -e "s|(?<=ge-proton).*|$gever|gi" "$pnpge/protonge/version"
|
||||
test -h "$pnbin/protonge" || ln -sf "$pnpge/protonge" "$pnbin"
|
||||
fi
|
||||
}
|
||||
|
||||
xwn () {
|
||||
export WINE_BRANCH=staging
|
||||
sudo mkdir -pm755 /etc/apt/keyrings && sudo curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" \
|
||||
&& sudo curl -fsSL -o "/etc/apt/sources.list.d/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" "https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"')/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" \
|
||||
&& sudo apt-get update && sudo apt-get install --install-recommends -y winehq-${WINE_BRANCH} \
|
||||
&& sudo curl -fsSL -o /usr/bin/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks" \
|
||||
&& sudo chmod 755 /usr/bin/winetricks \
|
||||
&& sudo curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo -e "\n$(basename $0): ERROR - $*" 1>&2
|
||||
echo -e "\nusage: $(basename $0)\n [-?a,--?add] [-?b,--?bld] [-?c,--?cmd] [-?d,--?dsk]\n [-?i,--?inf] [-?k,--?kil] [-?o,--?ovr] [-?p,--?prg]\n [-?s,--?stm] [-?t,--?trk] [-?u,--?cut] [-?v,--?ver]\n\n[?] = (p)roton, (w)ine\n (add) exe path to reg, (bld) build prefix,\n (cmd) prog menu, (dsk) desktop, (inf) exe info,\n (kil) kill wine, (ovr) overrides, (prg) exe list,\n (stm) steam, (trk) winetricks, (cut) shortcut,\n (ver) wine version\n" 1>&2
|
||||
}
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
usage "one option required!"
|
||||
else
|
||||
case $xarg in
|
||||
-xa|--xadd)
|
||||
# cross-fuction path add to registry based on exe
|
||||
xnint
|
||||
xnpre
|
||||
xpmn
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
ptadd="$(dirname "$pedir/$xmrtn")"
|
||||
ptadd="z:${ptadd////\\\\}"
|
||||
read -r -p 'prepend to system path? [y/N] ' chse
|
||||
clear
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xnreg='System\\CurrentControlSet\\Control\\Session Manager\\Environment'
|
||||
xmrtn='system.reg'
|
||||
else
|
||||
xnreg='Environment'
|
||||
xmrtn='user.reg'
|
||||
fi
|
||||
if [[ -z "$(pcre2grep -Mio "\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\".+?(?=\[.+?\])(?-s)" "$xnpfx/$xmrtn")" ]]; then
|
||||
perl -0777 -pi -e "s|(\[\Q${xnreg,,}\E\](?s).+?#time=(?-s).*)(?s)(.+?)(?=\[.+?\])(?-s)|\\1\n\"PATH\"=str\(2\):\"${ptadd//\\/\\\\}\"\\2|gi" "$xnpfx/$xmrtn"
|
||||
echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nPATH created successfully\n"
|
||||
elif [[ -z "$(pcre2grep -Mio "\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\"(?-s).*\Q${ptadd,,}\E[\;\"](?s).+?(?=\[.+?\])(?-s)" "$xnpfx/$xmrtn")" ]]; then
|
||||
perl -0777 -pi -e "s|(\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\")(?-s)(.*)(?s)(.+?)(?=\[.+?\])(?-s)|\\1${ptadd//\\/\\\\}\;\\2\\3|gi" "$xnpfx/$xmrtn"
|
||||
echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nPATH added successfully\n"
|
||||
else
|
||||
echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nalready in PATH\n"
|
||||
fi
|
||||
# \Q \E adds \ to non alphanums but variable with \E ends \Q
|
||||
# lowercase ${var,,} to avoid since path/reg not case sensitive
|
||||
# linux path is case sensitive so user must not create duplicates
|
||||
fi
|
||||
;;
|
||||
-xb|--xbld)
|
||||
# cross-function prefix builder
|
||||
xbld
|
||||
;;
|
||||
-xc|--xcmd)
|
||||
# cross-function standard tools menu
|
||||
xnset
|
||||
readarray -t i_mnus < <(printf '%s\n' "${pmenu[@]}" | perl -pe 's|/.*||gi' ; echo "quit")
|
||||
w_menu
|
||||
xmrtn="$(printf '%s\n' "${pmenu[@]}" | grep -Pio "(?<=$xmrtn/).*")"
|
||||
xnldr
|
||||
if [[ -f "${clprm[0]}" ]];then
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
cd "$(dirname "$pedir")" || exit
|
||||
xcmd+=("$xmrtn" "$pedir" "${clprm[@]:1}")
|
||||
else
|
||||
xcmd+=("$xmrtn" "${clprm[@]}")
|
||||
fi
|
||||
xlnch
|
||||
;;
|
||||
-xd|--xdsk)
|
||||
# cross-function wine desktop
|
||||
xnset
|
||||
xnldr
|
||||
xcmd+=("explorer.exe" "/desktop=shell,1024x768" "explorer.exe")
|
||||
xlnch
|
||||
;;
|
||||
-i|--install)
|
||||
# proton ge
|
||||
xpge
|
||||
xwn
|
||||
;;
|
||||
-xi|--xinf)
|
||||
# cross-fuction program info
|
||||
if [[ ! -f "${clprm[0]}" && ! -d "${clprm[0]}" ]]; then
|
||||
# don't menu prefix on supplied file or folder
|
||||
xnint
|
||||
xnpre
|
||||
fi
|
||||
if [[ ! -f "${clprm[0]}" ]]; then
|
||||
# offer to menu dll if no file given
|
||||
read -r -p 'query dll? [y/N] ' chse
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xflt="*.dll"
|
||||
fi
|
||||
fi
|
||||
xpmn
|
||||
IFS=$'\n'
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
if [[ $(readpe "$pedir/$xmrtn" 2>/dev/null) ]]; then
|
||||
# if file is PE print 32/64-bit and dll references
|
||||
myprnt+=("$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Piq 'PE32\+' && echo -e "FILE:\n$xmrtn\n \nPE HEADER:\n64-bit" || echo -e "FILE:\n$xmrtn\n \nPE HEADER:\n32-bit")")
|
||||
myprnt+=("$(echo -e ' \nVersion:' ; peres -v "$pedir/$xmrtn" 2>/dev/null | grep -Pio '(?<=Product Version:).*' | tr -d ' ')")
|
||||
# find dll references, filenames without spaces
|
||||
myprnt+=("$(echo -e ' \nREFERENCES:' ; strings "$pedir/$xmrtn" | grep -Pio '[^<>:"/\\|?*\s]+\.dll' | perl -pe 's|([^/]*\Z)|lc($1)|e' | sort -u ; echo ' ')")
|
||||
else
|
||||
myprnt+=("$(echo -e ' \nNot a 32/64-bit program, no information to provide\n ')")
|
||||
fi
|
||||
else
|
||||
myprnt+=("$(echo -e ' \nNo file found\n ')")
|
||||
fi
|
||||
printf '%s\n' "${myprnt[@]}"
|
||||
unset IFS myprnt
|
||||
;;
|
||||
-xk|--xkil)
|
||||
# cross-function wine kill, must select same as running
|
||||
xnset
|
||||
xcmd+=("wineserver" "-k")
|
||||
xlnch
|
||||
;;
|
||||
-xo|--xovr)
|
||||
# cross-function prefix override list
|
||||
xnint
|
||||
xnpre
|
||||
read -r -p 'per application? [y/N] ' chse
|
||||
clear
|
||||
IFS=$'\n'
|
||||
myprnt+=("$(echo -e "Prefix:\n$xnpfx\n ")")
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
# show existing per-application overrides
|
||||
myprnt+=("$(echo -e 'Per-application overrides:' ; pcre2grep -Mio '\[\Qsoftware\\wine\\appdefaults\\\E[^\\]+\Q\\dlloverrides\E\](?s).+?(?=\[.+?\])(?-s)' "$xnpfx/user.reg" | grep -Pio '(?<=appdefaults..).*(?=..dlloverrides)|\".*\"' && echo ' ' || echo -e 'None found\n ')")
|
||||
else
|
||||
# show existing prefix overrides
|
||||
myprnt+=("$(echo -e 'Global overrides:' ; pcre2grep -Mio '\[\Qsoftware\\wine\\dlloverrides\E\](?s).+?(?=\[.+?\])(?-s)' "$xnpfx/user.reg" | grep -Pio '\".*\"' && echo ' ' || echo -e 'None found\n ')")
|
||||
fi
|
||||
printf '%s\n' "${myprnt[@]}"
|
||||
unset IFS myprnt
|
||||
# A command like:
|
||||
# perl -pi -e 's/(\".*msvc.*\"=\")(.*),(.*)(")/\1\3,\2\4/g' user.reg
|
||||
# Swaps msvc entries (native,builtin) to (builtin,native)
|
||||
;;
|
||||
-xr|--xrun)
|
||||
# cross-fuction run program - 1st arg valid file to run, folder to menu,
|
||||
# neither (sys menu), 2nd arg... passed to exe
|
||||
xnset
|
||||
xpmn
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
xlyt
|
||||
# change to exe dir before run
|
||||
cd "$(dirname "$pedir/$xmrtn")" || exit
|
||||
xlnch
|
||||
fi
|
||||
;;
|
||||
-xs|--xstm)
|
||||
# cross-function steam launcher
|
||||
xstm
|
||||
;;
|
||||
-xt|--xtrk)
|
||||
# cross-function winetricks
|
||||
xnset
|
||||
# winetricks for selected wine/proton prefix
|
||||
if [[ ${#clprm[@]} -gt 0 ]]; then
|
||||
xcmd+=("winetricks" "${clprm[@]}")
|
||||
dbg="1"
|
||||
# use args if supplied, otherwise gui
|
||||
else
|
||||
xcmd+=("winetricks" "--gui")
|
||||
# protontricks may work better
|
||||
fi
|
||||
xlnch
|
||||
;;
|
||||
-xu|--xcut)
|
||||
# cross-function desktop shortcut
|
||||
if [[ -d "$desk" ]]; then
|
||||
xnset
|
||||
xpmn
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
xlyt
|
||||
# change to desktop dir before create icon
|
||||
cd "$desk" || exit
|
||||
read -r -e -p $'Shortcut Name?\x0a' -i "$(basename "${xmrtn/.*}")" chse
|
||||
# create desktop entry
|
||||
gendesk -f -n --name="$chse" --comment='created by wstart' --custom='Keywords=wine;proton;launcher;' --exec="bash -c 'cd \"$(dirname "$pedir/$xmrtn")\" ; $(printf '"%s" ' "${xcmd[@]}")'" --icon="$icon" --terminal=false --categories='Emulator;Game' --startupnotify=false --pkgname="$chse"
|
||||
chmod 755 "$chse".desktop
|
||||
fi
|
||||
else
|
||||
echo -e "Invalid desktop location: $desk\nPlease edit the script"
|
||||
fi
|
||||
;;
|
||||
-xv|--xver)
|
||||
# cross-function wine version
|
||||
xnint
|
||||
xnexe
|
||||
xnenv
|
||||
xcmd+=("wine" "--version")
|
||||
("${xcmd[@]}" &)
|
||||
;;
|
||||
-h|--help)
|
||||
echo -e "\n General usage: netris-proton -w? args\n -w? options for wine and -p? for proton.\n Type wstart by itself for command list.\n\n Edit script path variables as needed.\n bash, find, gendesk, grep, readpe,\n strings, winetricks, wrestool,\n pcre2grep, peres, perl needed by\n certain items.\n"
|
||||
;;
|
||||
-*|\*|*)
|
||||
# do_usage
|
||||
usage "invalid option $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
#TODO: Fix the warp-input startup problem
|
||||
if [ -z "$SESSION_ID" ]; then
|
||||
echo "Error: SESSION_ID environment variable is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#Open udp port to listed for QUIC events on
|
||||
export PORT=${PORT:-"8080"}
|
||||
|
||||
sudo -E /usr/bin/supervisord -c /etc/supervisord.conf
|
||||
@@ -1,42 +0,0 @@
|
||||
[supervisord]
|
||||
user=nestri
|
||||
nodaemon=true
|
||||
loglevel=info
|
||||
logfile=/tmp/supervisord.log
|
||||
pidfile=/tmp/supervisord.pid
|
||||
|
||||
[program:entrypoint]
|
||||
command=/etc/entrypoint.sh
|
||||
user=nestri
|
||||
logfile=/tmp/entrypoint.log
|
||||
pidfile=/tmp/entrypoint.pid
|
||||
stopsignal=INT
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
priority=1
|
||||
|
||||
[program:pulseaudio]
|
||||
user=nestri
|
||||
command=bash -c "until [ -S \"/tmp/.X11-unix/X${DISPLAY/:/}\" ]; do sleep 1; done; sudo /usr/bin/pulseaudio -k >/dev/null 2>&1 || sudo /usr/bin/pulseaudio --system --verbose --log-target=stderr --realtime=true --disallow-exit -L 'module-native-protocol-tcp auth-ip-acl=127.0.0.0/8 port=4713 auth-anonymous=1'"
|
||||
environment=DISPLAY=":0"
|
||||
logfile=/tmp/pulseaudio.log
|
||||
pidfile=/tmp/pulseaudio.pid
|
||||
stopsignal=INT
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
priority=10
|
||||
|
||||
[program:warp-input]
|
||||
command=bash -c "until [ -S \"/tmp/.X11-unix/X${DISPLAY/:/}\" ]; do sleep 1; done; /usr/bin/warp-input --namespace $SESSION_ID --bind '[::]:8080' https://fst.so:4443"
|
||||
logfile=/tmp/warp-input.log
|
||||
pidfile=/tmp/warp-input.pid
|
||||
stopsignal=INT
|
||||
user=nestri
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY=":0",SESSION_ID="%(ENV_SESSION_ID)s"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startretries=100
|
||||
redirect_stderr=true
|
||||
priority=20
|
||||
3
.vscode/settings.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"files.eol": "\n"
|
||||
}
|
||||
4
LICENSE
@@ -629,8 +629,8 @@ to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
Netris: The open-source cloud gaming platform for friends
|
||||
Copyright (C) 2024 Wanjohi Ryan
|
||||
Nestri: Your games, Your rules
|
||||
Copyright (C) 2023 WanjohiRyan
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
|
||||
186
README.md
@@ -1,38 +1,23 @@
|
||||
<div align="center">
|
||||
<div>
|
||||
|
||||
<a href="https://nestri.io" >
|
||||
<img height="160" src="/assets/logo.png">
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div align="center">
|
||||
<h1>
|
||||
<a href="https://nestri.io" >
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="/assets/logo-name-white.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="/assets/logo-name-black.png">
|
||||
<img alt="nestri logo name" src="/assets/logo-name-black.png">
|
||||
</picture>
|
||||
|
||||
<img src="/apps/www/public/images/next.png" alt="Nestri - What will you play next?">
|
||||
</a>
|
||||
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
An open-source cloud gaming platform built for you to play together with your friends. <br/> A GeForce NOW alternative that can be self-hosted.<br/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
Nestri is an open-source, self-hosted cloud gaming platform that allows you to play games in your web browser with friends. <strong>Built and shaped by our gaming community.</strong>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![][github-release-shield]][github-release-link]
|
||||
@@ -49,158 +34,21 @@ An open-source cloud gaming platform built for you to play together with your fr
|
||||
|
||||
|
||||
|
||||
<div align="center" >
|
||||
|
||||
[![][image-overview]][website-link]
|
||||
|
||||
</div>
|
||||
|
||||
## Features 🌟
|
||||
|
||||
As Nestri navigates through its _experimental_ phase, we're in the process of crafting and testing a variety of features for you:
|
||||
|
||||
1. **🎮 Proton-GE Compatibility:** We utilize Proton-GE for running games, offering extensive game compatibility and ensuring you can play a wide variety of titles.
|
||||
|
||||
2. **⚡ QUIC Protocol:** For input and video/audio transmission, we use QUIC via [MoQ][moq-github-url] to significantly reduce latency on variable networks, ensuring crisp visuals without sacrificing data or increasing latency.
|
||||
|
||||
3. **🔗 Session IDs:** With a `SESSION_ID`, we seamlessly tie your game progress, achievements, and devices without the need for logging into [nestri.io][website-link]. Our public CDNs, currently located in Europe (eu-north-1) and the US (us-east-1), further reduce latency for friends playing together from afar. More locations are on the way!
|
||||
|
||||
4. **🔄 Automatic Game Progress Sync:** Like Stadia's state share, we automatically sync your game progress based on the *.exe file you're running, allowing you to share your progress with friends via a link.
|
||||
|
||||
5. **👫 Co-op Gameplay:** Play co-op with up to 8 people, or play single player by sharing mouse and keyboard inputs seamlessly (similar to [neko][neko-url]).
|
||||
|
||||
6. **🌐 Cross-Platform Play:** Our platform is accessible on any device that can run a Chrome-based browser, including Edge, Chrome, Brave, and Arc. And you do not have to set up anything, it's all done and maintained for you.
|
||||
|
||||
7. **📊 Bandwidth Optimization:** Experience hardware-accelerated `VMAF` for optimized bandwidth, ensuring the best possible video quality. [Learn More][vmaf-cuda-link]
|
||||
|
||||
8. **🌟 ...and more:** Stay tuned as we continue to add features _sometimes inspired by platforms like Stadia_, to give you the best and most customizable gaming experience.
|
||||
|
||||
This platform is in an _experimental_ phase, and we're actively working on adding new features. Your feedback and support is very much appreciated.
|
||||
|
||||
> \[!IMPORTANT]
|
||||
>
|
||||
> If you're excited about what we're doing and want to support our journey, consider giving us a star ⭐ on our repository. Your support fuels our progress!. \~ ✨
|
||||
> More info coming soon!
|
||||
|
||||
|
||||
[![][image-star]][github-stars-link]
|
||||
|
||||
|
||||
## Getting Started 🎮
|
||||
|
||||
Whether you're looking to self-host Nestri or simply want to try it out without the need for your own GPU, we've got you covered. Choose the path that best suits your needs:
|
||||
|
||||
<!-- _You can always change your option later without losing game progress_ -->
|
||||
|
||||
| If you don't have a Nvidia GPU or prefer not to self-host, you can visit our website. No installation or set up required ! <br/> This is the perfect option for gamers looking to dive straight into the action without any setup. | [👉🏽 Get Access][website-link] |
|
||||
| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- |
|
||||
| If you're interested in self-hosting Nestri, continue reading for detailed instructions on how to get started. <br/> This option is ideal if you have your own Nvidia GPU and are comfortable with setting up and managing your own server. | [🛠️ Self Host Nestri](#self-hosting) |
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> Remember, flexibility is key with Nestri. You're free to switch between self-hosting and using `nestri.io` whenever you like, without losing your game progress. \~ 💡
|
||||
<a name="self-hosting"></a>
|
||||
|
||||
### Self-Hosting Nestri 🔨
|
||||
|
||||
For those interested in self-hosting, here are is what you need to get your own Nestri server up and running:
|
||||
|
||||
- **Nvidia GPU**: Unfortunately, this setup is exclusive to Nvidia GPUs. If you don't own one, consider renting from cloud services like AWS, GCP, or Vast.ai. We highly recommend this approach.
|
||||
|
||||
- **CUDA**: For GPU acceleration, CUDA version `12.0` or newer is required. Verify your CUDA installation by running `nvcc --version`.
|
||||
|
||||
- **Docker**: Ensure you have `docker` and `nvidia-docker` are up to date to avoid compatibility issues with CUDA. You can check your Docker version by running `docker --version` in your terminal.
|
||||
|
||||
- **GPU Driver**: Ensure your GPU drivers are up to date to avoid compatibility issues with CUDA. Nvidia driver version `520.56.06` or newer is required.
|
||||
|
||||
- **Xorg Display**: Your Nvidia GPU should not be attached to a running X display server. You can confirm this by running `nvidia-smi`.
|
||||
|
||||
- **Nvidia-DRM**: Make sure that the `nvidia-drm` module has been loaded and that the module is loaded with the flag `modeset=1`. Confirm this by running `sudo cat /sys/module/nvidia_drm/parameters/modeset`
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> Typically, if your setup meets the necessary CUDA requirements, the `nvidia-drm` module will already be loaded, particularly in AWS G4dn instances. \~ 💡
|
||||
|
||||
### Step-by-Step Guide
|
||||
|
||||
Follow these steps to get Nestri up and running on your system.
|
||||
|
||||
> \[!IMPORTANT]
|
||||
>
|
||||
> This is our pilot, there is a lot we haven't figured out yet. Please file an issue if anything comes up. \~ 🫂
|
||||
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> The setup process will become much simpler with the launch of our CLI tool, so stay tuned for that! In the meantime, you'll need to follow these manual steps.
|
||||
|
||||
#### Step 1: Navigate to Your Game Directory
|
||||
|
||||
First, change your directory to the location of your `.exe` file. For Steam games, this typically means:
|
||||
|
||||
```bash
|
||||
cd $HOME/.steam/steam/steamapps
|
||||
ls -la .
|
||||
```
|
||||
|
||||
#### Step 2: Generate a Session ID
|
||||
|
||||
Create a unique session ID using the following command:
|
||||
|
||||
```bash
|
||||
head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16
|
||||
```
|
||||
|
||||
This command generates a random 16-character string. Be sure to note this string carefully, as you'll need it for the next step.
|
||||
|
||||
#### Step 3: Launch the Nestri Server
|
||||
|
||||
With your SESSION_ID ready, insert it into the command below, replacing `<copy here>` with your actual session ID. Then, run the command to start the Nestri server:
|
||||
|
||||
```
|
||||
docker run --gpus all --device=/dev/dri --name nestri -it --entrypoint /bin/bash -e SESSION_ID=<copy here> -v "$(pwd)":/game -p 8080:8080/udp --cap-add=SYS_NICE --cap-add=SYS_ADMIN ghcr.io/nestriness/nestri/server:nightly
|
||||
```
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> Ensure UDP port 8080 is accessible from the internet. Use `ufw allow 8080/udp` or adjust your cloud provider's security group settings accordingly.
|
||||
|
||||
#### Step 4: Configure the Game within the Container
|
||||
|
||||
After executing the previous command, you'll be in a new shell within the container (example: `nestri@3f199ee68c01:~$`). Perform the following checks:
|
||||
|
||||
1. Verify the game is mounted by executing `ls -la /game`. If not, exit and ensure you've correctly mounted the game directory as a volume.
|
||||
2. Then, start the Netris server by running `/etc/startup.sh > /dev/null &`.
|
||||
|
||||
#### Step 5: Running Your Game
|
||||
|
||||
Wait for the `.X11-unix` directory to appear in `/tmp` (check with `ls -la /tmp`). Once it appears, you're ready to launch your game.
|
||||
|
||||
- With Proton-GE: `nestri-proton -pr <game>.exe`
|
||||
- With Wine: `nestri-proton -wr <game>.exe`
|
||||
|
||||
#### Step 6: Begin Playing
|
||||
|
||||
Finally, construct the play URL with your session ID:
|
||||
|
||||
```
|
||||
echo "https://nestri.io/play/$SESSION_ID"
|
||||
```
|
||||
|
||||
Navigate to this URL in your browser, click on the page to capture your mouse pointer, and start playing!
|
||||
|
||||
|
||||
[github-release-link]: https://github.com/wanjohiryan/netris/releases
|
||||
[github-release-shield]: https://img.shields.io/github/v/release/wanjohiryan/netris?color=369eff&labelColor=black&logo=github&style=flat-square
|
||||
[github-release-link]: https://github.com/nestriness/nestri/releases
|
||||
[github-release-shield]: https://img.shields.io/github/v/release/nestriness/nestri?color=369eff&labelColor=black&logo=github&style=flat-square
|
||||
[discord-shield]: https://img.shields.io/discord/1080111004698021909?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square
|
||||
[discord-link]: https://discord.com/invite/Y6etn3qKZ3
|
||||
[github-license-shield]: https://img.shields.io/github/license/wanjohiryan/netris?color=white&labelColor=black&style=flat-square
|
||||
[github-license-link]: https://github.com/wanjohiryan/netris/blob/main/LICENSE
|
||||
[github-stars-shield]: https://img.shields.io/github/stars/wanjohiryan/netris?color=ffcb47&labelColor=black&style=flat-square
|
||||
[github-stars-link]: https://github.com/wanjohiryan/netris/network/stargazers
|
||||
[github-license-shield]: https://img.shields.io/github/license/nestriness/nestri?color=white&labelColor=black&style=flat-square
|
||||
[github-license-link]: https://github.com/nestriness/nestri/blob/main/LICENSE
|
||||
[github-stars-shield]: https://img.shields.io/github/stars/nestriness/nestri?color=ffcb47&labelColor=black&style=flat-square
|
||||
[github-stars-link]: https://github.com/nestriness/nestri/network/stargazers
|
||||
[share-x-shield]: https://img.shields.io/badge/-share%20on%20x-black?labelColor=black&logo=x&logoColor=white&style=flat-square
|
||||
[share-x-link]: https://twitter.com/intent/tweet?text=Hey%2C%20check%20out%20this%20Github%20repository.%20It%20is%20an%20open-source%20self-hosted%20Geforce%20Now%20alternative.&url=https%3A%2F%2Fgithub.com%2Fwanjohiryan%2Fnetris
|
||||
[share-x-link]: https://twitter.com/intent/tweet?text=Hey%2C%20check%20out%20this%20Github%20repository.%20It%20is%20an%20open-source%20self-hosted%20Geforce%20Now%20alternative.&url=https%3A%2F%2Fgithub.com%2Fnestriness%2Fnestri
|
||||
[share-reddit-shield]: https://img.shields.io/badge/-share%20on%20reddit-black?labelColor=black&logo=reddit&logoColor=white&style=flat-square
|
||||
[share-reddit-link]: https://www.reddit.com/submit?title=Hey%2C%20check%20out%20this%20Github%20repository.%20It%20is%20an%20open-source%20self-hosted%20Geforce%20Now%20alternative.&url=https%3A%2F%2Fgithub.com%2Fwanjohiryan%2Fnetris
|
||||
[share-reddit-link]: https://www.reddit.com/submit?title=Hey%2C%20check%20out%20this%20Github%20repository.%20It%20is%20an%20open-source%20self-hosted%20Geforce%20Now%20alternative.&url=https%3A%2F%2Fgithub.com%2Fnestriness%2Fnestri
|
||||
[image-overview]: assets/banner.png
|
||||
[website-link]: https://nestri.io
|
||||
[neko-url]: https://github.com/m1k1o/neko
|
||||
|
||||
9
apps/docs/.eslintrc.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@nestri/eslint-config/next.js"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: true,
|
||||
},
|
||||
};
|
||||
36
apps/docs/.gitignore
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.yarn/install-state.gz
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# env files (can opt-in for commiting if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
36
apps/docs/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
BIN
apps/docs/app/favicon.ico
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
apps/docs/app/fonts/GeistMonoVF.woff
Normal file
BIN
apps/docs/app/fonts/GeistVF.woff
Normal file
39
apps/docs/app/globals.css
Normal file
@@ -0,0 +1,39 @@
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
31
apps/docs/app/layout.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { Metadata } from "next";
|
||||
import localFont from "next/font/local";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = localFont({
|
||||
src: "./fonts/GeistVF.woff",
|
||||
variable: "--font-geist-sans",
|
||||
});
|
||||
const geistMono = localFont({
|
||||
src: "./fonts/GeistMonoVF.woff",
|
||||
variable: "--font-geist-mono",
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${geistSans.variable} ${geistMono.variable}`}>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
188
apps/docs/app/page.module.css
Normal file
@@ -0,0 +1,188 @@
|
||||
.page {
|
||||
--gray-rgb: 0, 0, 0;
|
||||
--gray-alpha-200: rgba(var(--gray-rgb), 0.08);
|
||||
--gray-alpha-100: rgba(var(--gray-rgb), 0.05);
|
||||
|
||||
--button-primary-hover: #383838;
|
||||
--button-secondary-hover: #f2f2f2;
|
||||
|
||||
display: grid;
|
||||
grid-template-rows: 20px 1fr 20px;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
min-height: 100svh;
|
||||
padding: 80px;
|
||||
gap: 64px;
|
||||
font-synthesis: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.page {
|
||||
--gray-rgb: 255, 255, 255;
|
||||
--gray-alpha-200: rgba(var(--gray-rgb), 0.145);
|
||||
--gray-alpha-100: rgba(var(--gray-rgb), 0.06);
|
||||
|
||||
--button-primary-hover: #ccc;
|
||||
--button-secondary-hover: #1a1a1a;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
grid-row-start: 2;
|
||||
}
|
||||
|
||||
.main ol {
|
||||
font-family: var(--font-geist-mono);
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
letter-spacing: -0.01em;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
.main li:not(:last-of-type) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.main code {
|
||||
font-family: inherit;
|
||||
background: var(--gray-alpha-100);
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.ctas {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.ctas a {
|
||||
appearance: none;
|
||||
border-radius: 128px;
|
||||
height: 48px;
|
||||
padding: 0 20px;
|
||||
border: none;
|
||||
font-family: var(--font-geist-sans);
|
||||
border: 1px solid transparent;
|
||||
transition: background 0.2s, color 0.2s, border-color 0.2s;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
a.primary {
|
||||
background: var(--foreground);
|
||||
color: var(--background);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
a.secondary {
|
||||
border-color: var(--gray-alpha-200);
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
button.secondary {
|
||||
appearance: none;
|
||||
border-radius: 128px;
|
||||
height: 48px;
|
||||
padding: 0 20px;
|
||||
border: none;
|
||||
font-family: var(--font-geist-sans);
|
||||
border: 1px solid transparent;
|
||||
transition: background 0.2s, color 0.2s, border-color 0.2s;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
font-weight: 500;
|
||||
background: transparent;
|
||||
border-color: var(--gray-alpha-200);
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
font-family: var(--font-geist-sans);
|
||||
grid-row-start: 3;
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.footer img {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Enable hover only on non-touch devices */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
a.primary:hover {
|
||||
background: var(--button-primary-hover);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
a.secondary:hover {
|
||||
background: var(--button-secondary-hover);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.footer a:hover {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.page {
|
||||
padding: 32px;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.main {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main ol {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ctas {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ctas a {
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
a.secondary {
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.logo {
|
||||
filter: invert();
|
||||
}
|
||||
}
|
||||
99
apps/docs/app/page.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import Image from "next/image";
|
||||
import { Button } from "@nestri/ui/button";
|
||||
import styles from "./page.module.css";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<main className={styles.main}>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={180}
|
||||
height={38}
|
||||
priority
|
||||
/>
|
||||
<ol>
|
||||
<li>
|
||||
Get started by editing <code>app/page.tsx</code>
|
||||
</li>
|
||||
<li>Save and see your changes instantly.</li>
|
||||
</ol>
|
||||
|
||||
<div className={styles.ctas}>
|
||||
<a
|
||||
className={styles.primary}
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={styles.secondary}
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
<Button appName="docs" className={styles.secondary}>
|
||||
Open alert
|
||||
</Button>
|
||||
</main>
|
||||
<footer className={styles.footer}>
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/file-text.svg"
|
||||
alt="File icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/window.svg"
|
||||
alt="Window icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/globe.svg"
|
||||
alt="Globe icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
4
apps/docs/next.config.mjs
Normal file
@@ -0,0 +1,4 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
||||
27
apps/docs/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@nestri/docs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbo --port 3001",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestri/ui": "*",
|
||||
"react": "19.0.0-rc-f994737d14-20240522",
|
||||
"react-dom": "19.0.0-rc-f994737d14-20240522",
|
||||
"next": "15.0.0-rc.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestri/eslint-config": "*",
|
||||
"@nestri/typescript-config": "*",
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-rc.0"
|
||||
}
|
||||
}
|
||||
3
apps/docs/public/file-text.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.5 13.5V6.5V5.41421C14.5 5.149 14.3946 4.89464 14.2071 4.70711L9.79289 0.292893C9.60536 0.105357 9.351 0 9.08579 0H8H3H1.5V1.5V13.5C1.5 14.8807 2.61929 16 4 16H12C13.3807 16 14.5 14.8807 14.5 13.5ZM13 13.5V6.5H9.5H8V5V1.5H3V13.5C3 14.0523 3.44772 14.5 4 14.5H12C12.5523 14.5 13 14.0523 13 13.5ZM9.5 5V2.12132L12.3787 5H9.5ZM5.13 5.00062H4.505V6.25062H5.13H6H6.625V5.00062H6H5.13ZM4.505 8H5.13H11H11.625V9.25H11H5.13H4.505V8ZM5.13 11H4.505V12.25H5.13H11H11.625V11H11H5.13Z" fill="#666666"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 645 B |
10
apps/docs/public/globe.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_868_525)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.268 14.0934C11.9051 13.4838 13.2303 12.2333 13.9384 10.6469C13.1192 10.7941 12.2138 10.9111 11.2469 10.9925C11.0336 12.2005 10.695 13.2621 10.268 14.0934ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16ZM8.48347 14.4823C8.32384 14.494 8.16262 14.5 8 14.5C7.83738 14.5 7.67616 14.494 7.51654 14.4823C7.5132 14.4791 7.50984 14.4759 7.50647 14.4726C7.2415 14.2165 6.94578 13.7854 6.67032 13.1558C6.41594 12.5744 6.19979 11.8714 6.04101 11.0778C6.67605 11.1088 7.33104 11.125 8 11.125C8.66896 11.125 9.32395 11.1088 9.95899 11.0778C9.80021 11.8714 9.58406 12.5744 9.32968 13.1558C9.05422 13.7854 8.7585 14.2165 8.49353 14.4726C8.49016 14.4759 8.4868 14.4791 8.48347 14.4823ZM11.4187 9.72246C12.5137 9.62096 13.5116 9.47245 14.3724 9.28806C14.4561 8.87172 14.5 8.44099 14.5 8C14.5 7.55901 14.4561 7.12828 14.3724 6.71194C13.5116 6.52755 12.5137 6.37904 11.4187 6.27753C11.4719 6.83232 11.5 7.40867 11.5 8C11.5 8.59133 11.4719 9.16768 11.4187 9.72246ZM10.1525 6.18401C10.2157 6.75982 10.25 7.36805 10.25 8C10.25 8.63195 10.2157 9.24018 10.1525 9.81598C9.46123 9.85455 8.7409 9.875 8 9.875C7.25909 9.875 6.53877 9.85455 5.84749 9.81598C5.7843 9.24018 5.75 8.63195 5.75 8C5.75 7.36805 5.7843 6.75982 5.84749 6.18401C6.53877 6.14545 7.25909 6.125 8 6.125C8.74091 6.125 9.46123 6.14545 10.1525 6.18401ZM11.2469 5.00748C12.2138 5.08891 13.1191 5.20593 13.9384 5.35306C13.2303 3.7667 11.9051 2.51622 10.268 1.90662C10.695 2.73788 11.0336 3.79953 11.2469 5.00748ZM8.48347 1.51771C8.4868 1.52089 8.49016 1.52411 8.49353 1.52737C8.7585 1.78353 9.05422 2.21456 9.32968 2.84417C9.58406 3.42562 9.80021 4.12856 9.95899 4.92219C9.32395 4.89118 8.66896 4.875 8 4.875C7.33104 4.875 6.67605 4.89118 6.04101 4.92219C6.19978 4.12856 6.41594 3.42562 6.67032 2.84417C6.94578 2.21456 7.2415 1.78353 7.50647 1.52737C7.50984 1.52411 7.51319 1.52089 7.51653 1.51771C7.67615 1.50597 7.83738 1.5 8 1.5C8.16262 1.5 8.32384 1.50597 8.48347 1.51771ZM5.73202 1.90663C4.0949 2.51622 2.76975 3.7667 2.06159 5.35306C2.88085 5.20593 3.78617 5.08891 4.75309 5.00748C4.96639 3.79953 5.30497 2.73788 5.73202 1.90663ZM4.58133 6.27753C3.48633 6.37904 2.48837 6.52755 1.62761 6.71194C1.54392 7.12828 1.5 7.55901 1.5 8C1.5 8.44099 1.54392 8.87172 1.62761 9.28806C2.48837 9.47245 3.48633 9.62096 4.58133 9.72246C4.52807 9.16768 4.5 8.59133 4.5 8C4.5 7.40867 4.52807 6.83232 4.58133 6.27753ZM4.75309 10.9925C3.78617 10.9111 2.88085 10.7941 2.06159 10.6469C2.76975 12.2333 4.0949 13.4838 5.73202 14.0934C5.30497 13.2621 4.96639 12.2005 4.75309 10.9925Z" fill="#666666"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_868_525">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
1
apps/docs/public/next.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
10
apps/docs/public/vercel.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_977_547)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 3L18.5 17H2.5L10.5 3Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_977_547">
|
||||
<rect width="16" height="16" fill="white" transform="translate(2.5 2)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 367 B |
3
apps/docs/public/window.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5H14.5V12.5C14.5 13.0523 14.0523 13.5 13.5 13.5H2.5C1.94772 13.5 1.5 13.0523 1.5 12.5V2.5ZM0 1H1.5H14.5H16V2.5V12.5C16 13.8807 14.8807 15 13.5 15H2.5C1.11929 15 0 13.8807 0 12.5V2.5V1ZM3.75 5.5C4.16421 5.5 4.5 5.16421 4.5 4.75C4.5 4.33579 4.16421 4 3.75 4C3.33579 4 3 4.33579 3 4.75C3 5.16421 3.33579 5.5 3.75 5.5ZM7 4.75C7 5.16421 6.66421 5.5 6.25 5.5C5.83579 5.5 5.5 5.16421 5.5 4.75C5.5 4.33579 5.83579 4 6.25 4C6.66421 4 7 4.33579 7 4.75ZM8.75 5.5C9.16421 5.5 9.5 5.16421 9.5 4.75C9.5 4.33579 9.16421 4 8.75 4C8.33579 4 8 4.33579 8 4.75C8 5.16421 8.33579 5.5 8.75 5.5Z" fill="#666666"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 750 B |
18
apps/docs/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "@nestri/typescript-config/nextjs.json",
|
||||
"compilerOptions": {
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"next.config.mjs",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"name": "qwik-project-name",
|
||||
"scripts": {
|
||||
"build": "qwik build",
|
||||
"build.client": "vite build",
|
||||
"build.preview": "vite build --ssr src/entry.preview.tsx",
|
||||
"build.types": "tsc --incremental --noEmit",
|
||||
"dev": "vite --mode ssr",
|
||||
"dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
|
||||
"fmt": "prettier --write .",
|
||||
"fmt.check": "prettier --check .",
|
||||
"lint": "eslint \"src/**/*.ts*\"",
|
||||
"preview": "qwik build preview && vite preview --open",
|
||||
"start": "vite --open --mode ssr",
|
||||
"deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'",
|
||||
"qwik": "qwik"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@builder.io/qwik": "^1.5.1",
|
||||
"@builder.io/qwik-city": "^1.5.1",
|
||||
"@types/eslint": "^8.56.5",
|
||||
"@types/node": "^20.11.24",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-qwik": "^1.5.1",
|
||||
"prettier": "^3.2.5",
|
||||
"typescript": "5.3.3",
|
||||
"undici": "*",
|
||||
"vite": "^5.1.4",
|
||||
"vite-tsconfig-paths": "^4.2.1"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"sharp"
|
||||
],
|
||||
"trustedDependencies-annotation": "Needed for bun to allow running install scripts",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=10.0.0",
|
||||
"pnpm": ">=8.0.0",
|
||||
"yarn": ">=3.0.0"
|
||||
},
|
||||
"engines-annotation": "Mostly required by sharp which needs a Node-API v9 compatible runtime",
|
||||
"private": true,
|
||||
"type": "module"
|
||||
}
|
||||
@@ -35,7 +35,7 @@ module.exports = {
|
||||
"prefer-spread": "off",
|
||||
"no-case-declarations": "off",
|
||||
"no-console": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["warn"],
|
||||
"@typescript-eslint/no-unused-vars": ["error"],
|
||||
"@typescript-eslint/consistent-type-imports": "warn",
|
||||
"@typescript-eslint/no-unnecessary-condition": "warn",
|
||||
},
|
||||
|
||||
3
apps/www/.gitignore
vendored
@@ -39,6 +39,3 @@ lerna-debug.log*
|
||||
# Yarn
|
||||
.yarn/*
|
||||
!.yarn/releases
|
||||
|
||||
# Vercel
|
||||
.vercel
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export default {
|
||||
plugins: ['prettier-plugin-tailwindcss'],
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
# Qwik City App ⚡️
|
||||
|
||||
- [Qwik Docs](https://qwik.builder.io/)
|
||||
- [Discord](https://qwik.builder.io/chat)
|
||||
- [Qwik GitHub](https://github.com/BuilderIO/qwik)
|
||||
- [Qwik Docs](https://qwik.dev/)
|
||||
- [Discord](https://qwik.dev/chat)
|
||||
- [Qwik GitHub](https://github.com/QwikDev/qwik)
|
||||
- [@QwikDev](https://twitter.com/QwikDev)
|
||||
- [Vite](https://vitejs.dev/)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## Project Structure
|
||||
|
||||
This project is using Qwik with [QwikCity](https://qwik.builder.io/qwikcity/overview/). QwikCity is just an extra set of tools on top of Qwik to make it easier to build a full site, including directory-based routing, layouts, and more.
|
||||
This project is using Qwik with [QwikCity](https://qwik.dev/qwikcity/overview/). QwikCity is just an extra set of tools on top of Qwik to make it easier to build a full site, including directory-based routing, layouts, and more.
|
||||
|
||||
Inside your project, you'll see the following directory structure:
|
||||
|
||||
@@ -24,7 +24,7 @@ Inside your project, you'll see the following directory structure:
|
||||
└── ...
|
||||
```
|
||||
|
||||
- `src/routes`: Provides the directory-based routing, which can include a hierarchy of `layout.tsx` layout files, and an `index.tsx` file as the page. Additionally, `index.ts` files are endpoints. Please see the [routing docs](https://qwik.builder.io/qwikcity/routing/overview/) for more info.
|
||||
- `src/routes`: Provides the directory-based routing, which can include a hierarchy of `layout.tsx` layout files, and an `index.tsx` file as the page. Additionally, `index.ts` files are endpoints. Please see the [routing docs](https://qwik.dev/qwikcity/routing/overview/) for more info.
|
||||
|
||||
- `src/components`: Recommended directory for components.
|
||||
|
||||
@@ -32,10 +32,10 @@ Inside your project, you'll see the following directory structure:
|
||||
|
||||
## Add Integrations and deployment
|
||||
|
||||
Use the `pnpm qwik add` command to add additional integrations. Some examples of integrations includes: Cloudflare, Netlify or Express Server, and the [Static Site Generator (SSG)](https://qwik.builder.io/qwikcity/guides/static-site-generation/).
|
||||
Use the `bun qwik add` command to add additional integrations. Some examples of integrations includes: Cloudflare, Netlify or Express Server, and the [Static Site Generator (SSG)](https://qwik.dev/qwikcity/guides/static-site-generation/).
|
||||
|
||||
```shell
|
||||
pnpm qwik add # or `pnpm qwik add`
|
||||
bun qwik add # or `bun qwik add`
|
||||
```
|
||||
|
||||
## Development
|
||||
@@ -43,7 +43,7 @@ pnpm qwik add # or `pnpm qwik add`
|
||||
Development mode uses [Vite's development server](https://vitejs.dev/). The `dev` command will server-side render (SSR) the output during development.
|
||||
|
||||
```shell
|
||||
npm start # or `pnpm start`
|
||||
npm start # or `bun start`
|
||||
```
|
||||
|
||||
> Note: during dev mode, Vite may request a significant number of `.js` files. This does not represent a Qwik production build.
|
||||
@@ -53,7 +53,7 @@ npm start # or `pnpm start`
|
||||
The preview command will create a production build of the client modules, a production build of `src/entry.preview.tsx`, and run a local server. The preview server is only for convenience to preview a production build locally and should not be used as a production server.
|
||||
|
||||
```shell
|
||||
pnpm preview # or `pnpm preview`
|
||||
bun preview # or `bun preview`
|
||||
```
|
||||
|
||||
## Production
|
||||
@@ -61,49 +61,5 @@ pnpm preview # or `pnpm preview`
|
||||
The production build will generate client and server modules by running both client and server build commands. The build command will use Typescript to run a type check on the source code.
|
||||
|
||||
```shell
|
||||
pnpm build # or `pnpm build`
|
||||
bun build # or `bun build`
|
||||
```
|
||||
|
||||
## Vercel Edge
|
||||
|
||||
This starter site is configured to deploy to [Vercel Edge Functions](https://vercel.com/docs/concepts/functions/edge-functions), which means it will be rendered at an edge location near to your users.
|
||||
|
||||
## Installation
|
||||
|
||||
The adaptor will add a new `vite.config.ts` within the `adapters/` directory, and a new entry file will be created, such as:
|
||||
|
||||
```
|
||||
└── adapters/
|
||||
└── vercel-edge/
|
||||
└── vite.config.ts
|
||||
└── src/
|
||||
└── entry.vercel-edge.tsx
|
||||
```
|
||||
|
||||
Additionally, within the `package.json`, the `build.server` script will be updated with the Vercel Edge build.
|
||||
|
||||
## Production build
|
||||
|
||||
To build the application for production, use the `build` command, this command will automatically run `pnpm build.server` and `pnpm build.client`:
|
||||
|
||||
```shell
|
||||
pnpm build
|
||||
```
|
||||
|
||||
[Read the full guide here](https://github.com/BuilderIO/qwik/blob/main/starters/adapters/vercel-edge/README.md)
|
||||
|
||||
## Dev deploy
|
||||
|
||||
To deploy the application for development:
|
||||
|
||||
```shell
|
||||
pnpm deploy
|
||||
```
|
||||
|
||||
Notice that you might need a [Vercel account](https://docs.Vercel.com/get-started/) in order to complete this step!
|
||||
|
||||
## Production deploy
|
||||
|
||||
The project is ready to be deployed to Vercel. However, you will need to create a git repository and push the code to it.
|
||||
|
||||
You can [deploy your site to Vercel](https://vercel.com/docs/concepts/deployments/overview) either via a Git provider integration or through the Vercel CLI.
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { vercelEdgeAdapter } from "@builder.io/qwik-city/adapters/vercel-edge/vite";
|
||||
import { extendConfig } from "@builder.io/qwik-city/vite";
|
||||
import baseConfig from "../../vite.config";
|
||||
|
||||
export default extendConfig(baseConfig, () => {
|
||||
return {
|
||||
build: {
|
||||
ssr: true,
|
||||
rollupOptions: {
|
||||
input: ["src/entry.vercel-edge.tsx", "@qwik-city-plan"],
|
||||
},
|
||||
outDir: ".vercel/output/functions/_qwik-city.func",
|
||||
},
|
||||
plugins: [vercelEdgeAdapter()],
|
||||
};
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-qwik-empty-starter",
|
||||
"description": "App with Routing built-in ready to create your app",
|
||||
"name": "@nestri/www",
|
||||
"description": "Website for Nestri",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
@@ -15,9 +15,8 @@
|
||||
"build": "qwik build",
|
||||
"build.client": "vite build",
|
||||
"build.preview": "vite build --ssr src/entry.preview.tsx",
|
||||
"build.server": "vite build -c adapters/vercel-edge/vite.config.ts",
|
||||
"build.types": "tsc --incremental --noEmit",
|
||||
"deploy": "vercel deploy",
|
||||
"deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'",
|
||||
"dev": "vite --mode ssr",
|
||||
"dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
|
||||
"fmt": "prettier --write .",
|
||||
@@ -28,31 +27,18 @@
|
||||
"qwik": "qwik"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@builder.io/qwik": "^1.5.1",
|
||||
"@builder.io/qwik-city": "^1.5.1",
|
||||
"@builder.io/qwik-react": "0.5.0",
|
||||
"@types/eslint": "^8.56.5",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/react": "^18.2.28",
|
||||
"@types/react-dom": "^18.2.13",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-qwik": "^1.5.1",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.5.4",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tailwindcss": "3.3.3",
|
||||
"typescript": "5.3.3",
|
||||
"@builder.io/qwik": "^1.8.0",
|
||||
"@builder.io/qwik-city": "^1.8.0",
|
||||
"@types/eslint": "8.56.10",
|
||||
"@types/node": "20.14.11",
|
||||
"@typescript-eslint/eslint-plugin": "7.16.1",
|
||||
"@typescript-eslint/parser": "7.16.1",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-qwik": "^1.8.0",
|
||||
"prettier": "3.3.3",
|
||||
"typescript": "5.4.5",
|
||||
"undici": "*",
|
||||
"vercel": "^29.1.1",
|
||||
"vite": "^5.1.4",
|
||||
"vite": "5.3.5",
|
||||
"vite-tsconfig-paths": "^4.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/geist-sans": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
9347
apps/www/pnpm-lock.yaml
generated
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
Before Width: | Height: | Size: 23 KiB |
1
apps/www/public/favicon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 500 500"><g clip-path="url(#a)"><circle cx="250" cy="250" r="250" fill="#fff"/><path fill="#18B6F6" d="m367.87 418.45-61.17-61.18-.94.13v-.67L175.7 227.53l32.05-31.13L188.9 87.73 99.56 199.09c-15.22 15.42-18.03 40.51-7.08 59.03l55.83 93.11a46.82 46.82 0 0 0 40.73 22.81l27.65-.27 151.18 44.68Z"/><path fill="#AC7EF4" d="m401.25 196.94-12.29-22.81-6.41-11.67-2.54-4.56-.26.26-33.66-58.63a47.07 47.07 0 0 0-41.27-23.75l-29.51.8-88.01.28a47.07 47.07 0 0 0-40.33 23.34L93.4 207l95.76-119.54L314.7 226.19l-22.3 22.67 13.35 108.54.13-.26v.26h-.26l.26.27 10.42 10.2 50.62 49.78c2.13 2 5.6-.4 4.13-2.96l-31.25-61.85 54.5-101.3 1.73-2c.67-.81 1.33-1.62 1.87-2.42a46.8 46.8 0 0 0 3.34-50.18Z"/><path fill="#fff" d="M315.1 225.65 189.18 87.6l17.9 108.14L175 227l130.5 130.27-11.75-108.14 21.37-23.48Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h500v500H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 947 B |
BIN
apps/www/public/images/next.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
4
apps/www/qwik.env.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// This file can be used to add references for global types like `vite/client`.
|
||||
|
||||
// Add global `vite/client` types. For more info, see: https://vitejs.dev/guide/features#client-types
|
||||
/// <reference types="vite/client" />
|
||||
@@ -14,7 +14,7 @@ export const RouterHead = component$(() => {
|
||||
|
||||
<link rel="canonical" href={loc.url.href} />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
|
||||
{head.meta.map((m) => (
|
||||
<meta key={m.key} {...m} />
|
||||
@@ -25,7 +25,23 @@ export const RouterHead = component$(() => {
|
||||
))}
|
||||
|
||||
{head.styles.map((s) => (
|
||||
<style key={s.key} {...s.props} dangerouslySetInnerHTML={s.style} />
|
||||
<style
|
||||
key={s.key}
|
||||
{...s.props}
|
||||
{...(s.props?.dangerouslySetInnerHTML
|
||||
? {}
|
||||
: { dangerouslySetInnerHTML: s.style })}
|
||||
/>
|
||||
))}
|
||||
|
||||
{head.scripts.map((s) => (
|
||||
<script
|
||||
key={s.key}
|
||||
{...s.props}
|
||||
{...(s.props?.dangerouslySetInnerHTML
|
||||
? {}
|
||||
: { dangerouslySetInnerHTML: s.script })}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
import { createQwikCity } from "@builder.io/qwik-city/middleware/node";
|
||||
import qwikCityPlan from "@qwik-city-plan";
|
||||
// make sure qwikCityPlan is imported before entry
|
||||
import render from "./entry.ssr";
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,5 +26,8 @@ export default function (opts: RenderToStreamOptions) {
|
||||
lang: "en-us",
|
||||
...opts.containerAttributes,
|
||||
},
|
||||
serverData: {
|
||||
...opts.serverData,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* It's the entry point for Vercel Edge when building for production.
|
||||
*
|
||||
* Learn more about the Vercel Edge integration here:
|
||||
* - https://qwik.builder.io/docs/deployments/vercel-edge/
|
||||
*
|
||||
*/
|
||||
import {
|
||||
createQwikCity,
|
||||
type PlatformVercel,
|
||||
} from "@builder.io/qwik-city/middleware/vercel-edge";
|
||||
import qwikCityPlan from "@qwik-city-plan";
|
||||
import { manifest } from "@qwik-client-manifest";
|
||||
import render from "./entry.ssr";
|
||||
|
||||
declare global {
|
||||
interface QwikCityPlatform extends PlatformVercel {}
|
||||
}
|
||||
|
||||
export default createQwikCity({ render, qwikCityPlan, manifest });
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Tailwind CSS imports
|
||||
* View the full documentation at https://tailwindcss.com
|
||||
*/
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html *,
|
||||
html *::after,
|
||||
html *::before {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
ServiceWorkerRegister,
|
||||
} from "@builder.io/qwik-city";
|
||||
import { RouterHead } from "./components/router-head/router-head";
|
||||
import { isDev } from "@builder.io/qwik/build";
|
||||
|
||||
import "./global.css";
|
||||
import "@fontsource/geist-sans/400.css";
|
||||
|
||||
export default component$(() => {
|
||||
/**
|
||||
@@ -20,13 +20,18 @@ export default component$(() => {
|
||||
return (
|
||||
<QwikCityProvider>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta charset="utf-8" />
|
||||
{!isDev && (
|
||||
<link
|
||||
rel="manifest"
|
||||
href={`${import.meta.env.BASE_URL}manifest.json`}
|
||||
/>
|
||||
)}
|
||||
<RouterHead />
|
||||
</head>
|
||||
<body lang="en" class="min-h-screen font-sans antialiased">
|
||||
<body lang="en">
|
||||
<RouterOutlet />
|
||||
<ServiceWorkerRegister />
|
||||
{!isDev && <ServiceWorkerRegister />}
|
||||
</body>
|
||||
</QwikCityProvider>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
import { component$ } from "@builder.io/qwik";
|
||||
import type { DocumentHead } from "@builder.io/qwik-city";
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<div class='justify-center items-center w-screen h-screen flex flex-col gap-3' >
|
||||
<h1 class='text-3xl' >Hi 👋</h1>
|
||||
<p class='text-xl' >
|
||||
<>
|
||||
<h1>Hi 👋</h1>
|
||||
<div>
|
||||
Can't wait to see what you build with qwik!
|
||||
<br />
|
||||
Happy coding.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export const head: DocumentHead = {
|
||||
title: "Welcome to Qwik",
|
||||
meta: [
|
||||
{
|
||||
name: "description",
|
||||
content: "Qwik site description",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { component$, Slot } from "@builder.io/qwik";
|
||||
import type { RequestHandler } from "@builder.io/qwik-city";
|
||||
import type { DocumentHead } from "@builder.io/qwik-city";
|
||||
|
||||
export const onGet: RequestHandler = async ({ cacheControl }) => {
|
||||
// Control caching for this request for best performance and to reduce hosting costs:
|
||||
// https://qwik.builder.io/docs/caching/
|
||||
// https://qwik.dev/docs/caching/
|
||||
cacheControl({
|
||||
// Always serve a cached response by default, up to a week stale
|
||||
staleWhileRevalidate: 60 * 60 * 24 * 7,
|
||||
@@ -16,14 +15,3 @@ export const onGet: RequestHandler = async ({ cacheControl }) => {
|
||||
export default component$(() => {
|
||||
return <Slot />;
|
||||
});
|
||||
|
||||
|
||||
export const head: DocumentHead = {
|
||||
title: "netris.me/dev | Build the future of gaming",
|
||||
meta: [
|
||||
{
|
||||
name: "description",
|
||||
content: "Play with your friends right from your browser",
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* The service-worker.ts file is used to have state of the art prefetching.
|
||||
* https://qwik.builder.io/qwikcity/prefetching/overview/
|
||||
* https://qwik.dev/qwikcity/prefetching/overview/
|
||||
*
|
||||
* Qwik uses a service worker to speed up your site and reduce latency, ie, not used in the traditional way of offline.
|
||||
* You can also use this file to add more functionality that runs in the service worker.
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: [
|
||||
"Geist Sans",
|
||||
"ui-sans-serif",
|
||||
"system-ui",
|
||||
"-apple-system",
|
||||
"BlinkMacSystemFont",
|
||||
"Inter",
|
||||
"Segoe UI",
|
||||
"Roboto",
|
||||
"sans-serif",
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
"Segoe UI Symbol",
|
||||
"Noto Color Emoji",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
@@ -9,14 +9,13 @@
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "Bundler",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": true,
|
||||
"isolatedModules": true,
|
||||
"outDir": "tmp",
|
||||
"noEmit": true,
|
||||
"types": ["node", "vite/client"],
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"headers": [
|
||||
{
|
||||
"source": "/build/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=31536000, s-maxage=31536000, immutable"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,39 +7,45 @@ import { qwikVite } from "@builder.io/qwik/optimizer";
|
||||
import { qwikCity } from "@builder.io/qwik-city/vite";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import pkg from "./package.json";
|
||||
import { qwikReact } from "@builder.io/qwik-react/vite";
|
||||
|
||||
type PkgDep = Record<string, string>;
|
||||
const { dependencies = {}, devDependencies = {} } = pkg as any as {
|
||||
dependencies: Record<string, string>;
|
||||
devDependencies: Record<string, string>;
|
||||
dependencies: PkgDep;
|
||||
devDependencies: PkgDep;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
errorOnDuplicatesPkgDeps(devDependencies, dependencies);
|
||||
|
||||
/**
|
||||
* Note that Vite normally starts from `index.html` but the qwikCity plugin makes start at `src/entry.ssr.tsx` instead.
|
||||
*/
|
||||
|
||||
export default defineConfig(({ command, mode }): UserConfig => {
|
||||
return {
|
||||
plugins: [qwikCity(), qwikVite(), tsconfigPaths(), qwikReact()],
|
||||
plugins: [qwikCity(), qwikVite(), tsconfigPaths()],
|
||||
// This tells Vite which dependencies to pre-build in dev mode.
|
||||
optimizeDeps: {
|
||||
// Put problematic deps that break bundling here, mostly those with binaries.
|
||||
// For example ['better-sqlite3'] if you use that in server functions.
|
||||
exclude: [],
|
||||
},
|
||||
// This tells Vite how to bundle the server code.
|
||||
ssr:
|
||||
command === "build" && mode === "production"
|
||||
? {
|
||||
// All dev dependencies should be bundled in the server build
|
||||
noExternal: Object.keys(devDependencies),
|
||||
// Anything marked as a dependency will not be bundled
|
||||
// These should only be production binary deps (including deps of deps), CLI deps, and their module graph
|
||||
// If a dep-of-dep needs to be external, add it here
|
||||
// For example, if something uses `bcrypt` but you don't have it as a dep, you can write
|
||||
// external: [...Object.keys(dependencies), 'bcrypt']
|
||||
external: Object.keys(dependencies),
|
||||
}
|
||||
: undefined,
|
||||
|
||||
/**
|
||||
* This is an advanced setting. It improves the bundling of your server code. To use it, make sure you understand when your consumed packages are dependencies or dev dependencies. (otherwise things will break in production)
|
||||
*/
|
||||
// ssr:
|
||||
// command === "build" && mode === "production"
|
||||
// ? {
|
||||
// // All dev dependencies should be bundled in the server build
|
||||
// noExternal: Object.keys(devDependencies),
|
||||
// // Anything marked as a dependency will not be bundled
|
||||
// // These should only be production binary deps (including deps of deps), CLI deps, and their module graph
|
||||
// // If a dep-of-dep needs to be external, add it here
|
||||
// // For example, if something uses `bcrypt` but you don't have it as a dep, you can write
|
||||
// // external: [...Object.keys(dependencies), 'bcrypt']
|
||||
// external: Object.keys(dependencies),
|
||||
// }
|
||||
// : undefined,
|
||||
|
||||
server: {
|
||||
headers: {
|
||||
// Don't cache the server response in dev mode
|
||||
@@ -54,3 +60,47 @@ export default defineConfig(({ command, mode }): UserConfig => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// *** utils ***
|
||||
|
||||
/**
|
||||
* Function to identify duplicate dependencies and throw an error
|
||||
* @param {Object} devDependencies - List of development dependencies
|
||||
* @param {Object} dependencies - List of production dependencies
|
||||
*/
|
||||
function errorOnDuplicatesPkgDeps(
|
||||
devDependencies: PkgDep,
|
||||
dependencies: PkgDep,
|
||||
) {
|
||||
let msg = "";
|
||||
// Create an array 'duplicateDeps' by filtering devDependencies.
|
||||
// If a dependency also exists in dependencies, it is considered a duplicate.
|
||||
const duplicateDeps = Object.keys(devDependencies).filter(
|
||||
(dep) => dependencies[dep],
|
||||
);
|
||||
|
||||
// include any known qwik packages
|
||||
const qwikPkg = Object.keys(dependencies).filter((value) =>
|
||||
/qwik/i.test(value),
|
||||
);
|
||||
|
||||
// any errors for missing "qwik-city-plan"
|
||||
// [PLUGIN_ERROR]: Invalid module "@qwik-city-plan" is not a valid package
|
||||
msg = `Move qwik packages ${qwikPkg.join(", ")} to devDependencies`;
|
||||
|
||||
if (qwikPkg.length > 0) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
// Format the error message with the duplicates list.
|
||||
// The `join` function is used to represent the elements of the 'duplicateDeps' array as a comma-separated string.
|
||||
msg = `
|
||||
Warning: The dependency "${duplicateDeps.join(", ")}" is listed in both "devDependencies" and "dependencies".
|
||||
Please move the duplicated dependencies to "devDependencies" only and remove it from "dependencies"
|
||||
`;
|
||||
|
||||
// Throw an error with the constructed message.
|
||||
if (duplicateDeps.length > 0) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
assets/logo.png
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 46 KiB |
296
base.Dockerfile
@@ -1,296 +0,0 @@
|
||||
# This builds and updates the screen recorder we use on Netris
|
||||
# From https://git.dec05eba.com/gpu-screen-recorder
|
||||
FROM ubuntu:23.10
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
TIMEZONE=Africa/Nairobi \
|
||||
XDG_RUNTIME_DIR=/tmp/runtime-ubuntu \
|
||||
DISPLAY=:0 \
|
||||
PULSE_SERVER=unix:/run/pulse/native
|
||||
# WAYLAND_DISPLAY=wayland-0
|
||||
|
||||
# Install fundamental packages
|
||||
RUN apt-get clean \
|
||||
&& apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
apt-transport-https \
|
||||
apt-utils \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg \
|
||||
locales \
|
||||
make \
|
||||
software-properties-common \
|
||||
wget \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& locale-gen en_US.UTF-8
|
||||
|
||||
# Set locales
|
||||
ENV LANG=en_US.UTF-8 \
|
||||
LANGUAGE=en_US:en \
|
||||
LC_ALL=en_US.UTF-8
|
||||
|
||||
# Install operating system libraries or packages
|
||||
RUN dpkg --add-architecture i386 \
|
||||
&& apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
alsa-base \
|
||||
alsa-utils \
|
||||
cups-browsed \
|
||||
cups-bsd \
|
||||
cups-common \
|
||||
cups-filters \
|
||||
printer-driver-cups-pdf \
|
||||
file \
|
||||
bzip2 \
|
||||
gzip \
|
||||
xz-utils \
|
||||
unar \
|
||||
rar \
|
||||
unrar \
|
||||
zip \
|
||||
unzip \
|
||||
zstd \
|
||||
gcc \
|
||||
git \
|
||||
jq \
|
||||
python3 \
|
||||
python3-cups \
|
||||
python3-numpy \
|
||||
ssl-cert \
|
||||
nano \
|
||||
vim \
|
||||
htop \
|
||||
fakeroot \
|
||||
fonts-dejavu \
|
||||
fonts-freefont-ttf \
|
||||
fonts-hack \
|
||||
fonts-liberation \
|
||||
fonts-noto \
|
||||
fonts-noto-cjk \
|
||||
fonts-noto-cjk-extra \
|
||||
fonts-noto-color-emoji \
|
||||
fonts-noto-extra \
|
||||
fonts-noto-ui-extra \
|
||||
fonts-noto-hinted \
|
||||
fonts-noto-mono \
|
||||
fonts-noto-unhinted \
|
||||
fonts-opensymbol \
|
||||
fonts-symbola \
|
||||
fonts-ubuntu \
|
||||
lame \
|
||||
less \
|
||||
libavcodec-extra \
|
||||
libpulse0 \
|
||||
pulseaudio \
|
||||
supervisor \
|
||||
net-tools \
|
||||
packagekit-tools \
|
||||
pkg-config \
|
||||
mesa-utils \
|
||||
va-driver-all \
|
||||
va-driver-all:i386 \
|
||||
i965-va-driver-shaders \
|
||||
i965-va-driver-shaders:i386 \
|
||||
intel-media-va-driver-non-free \
|
||||
intel-media-va-driver-non-free:i386 \
|
||||
libva2 \
|
||||
libva2:i386 \
|
||||
vainfo \
|
||||
vdpau-driver-all \
|
||||
vdpau-driver-all:i386 \
|
||||
vdpauinfo \
|
||||
mesa-vulkan-drivers \
|
||||
mesa-vulkan-drivers:i386 \
|
||||
libvulkan-dev \
|
||||
libvulkan-dev:i386 \
|
||||
vulkan-tools \
|
||||
ocl-icd-libopencl1 \
|
||||
clinfo \
|
||||
dbus-user-session \
|
||||
dbus-x11 \
|
||||
libdbus-c++-1-0v5 \
|
||||
xkb-data \
|
||||
xauth \
|
||||
xbitmaps \
|
||||
xdg-user-dirs \
|
||||
xdg-utils \
|
||||
xfonts-base \
|
||||
xfonts-scalable \
|
||||
xinit \
|
||||
xsettingsd \
|
||||
libxrandr-dev \
|
||||
x11-xkb-utils \
|
||||
x11-xserver-utils \
|
||||
x11-utils \
|
||||
x11-apps \
|
||||
xserver-xorg-input-all \
|
||||
xserver-xorg-input-wacom \
|
||||
xserver-xorg-video-all \
|
||||
xserver-xorg-video-intel \
|
||||
xserver-xorg-video-qxl \
|
||||
# Install OpenGL libraries
|
||||
libxau6 \
|
||||
libxau6:i386 \
|
||||
libxdmcp6 \
|
||||
libxdmcp6:i386 \
|
||||
libxcb1 \
|
||||
libxcb1:i386 \
|
||||
libxext6 \
|
||||
libxext6:i386 \
|
||||
libx11-6 \
|
||||
libx11-6:i386 \
|
||||
libxv1 \
|
||||
libxv1:i386 \
|
||||
libxtst6 \
|
||||
libxtst6:i386 \
|
||||
libglvnd0 \
|
||||
libglvnd0:i386 \
|
||||
libgl1 \
|
||||
libgl1:i386 \
|
||||
libglx0 \
|
||||
libglx0:i386 \
|
||||
libegl1 \
|
||||
libegl1:i386 \
|
||||
libgles2 \
|
||||
libgles2:i386 \
|
||||
libglu1 \
|
||||
libglu1:i386 \
|
||||
libsm6 \
|
||||
libsm6:i386 \
|
||||
mesa-utils \
|
||||
mesa-utils-extra \
|
||||
xcvt \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& echo "/usr/local/nvidia/lib" >> /etc/ld.so.conf.d/nvidia.conf \
|
||||
&& echo "/usr/local/nvidia/lib64" >> /etc/ld.so.conf.d/nvidia.conf \
|
||||
# Configure OpenCL manually
|
||||
&& mkdir -pm755 /etc/OpenCL/vendors \
|
||||
&& echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
|
||||
# Configure Vulkan manually
|
||||
&& VULKAN_API_VERSION=$(dpkg -s libvulkan1 | grep -oP 'Version: [0-9|\.]+' | grep -oP '[0-9]+(\.[0-9]+)(\.[0-9]+)') \
|
||||
&& mkdir -pm755 /etc/vulkan/icd.d/ \
|
||||
&& echo "{\n\
|
||||
\"file_format_version\" : \"1.0.0\",\n\
|
||||
\"ICD\": {\n\
|
||||
\"library_path\": \"libGLX_nvidia.so.0\",\n\
|
||||
\"api_version\" : \"${VULKAN_API_VERSION}\"\n\
|
||||
}\n\
|
||||
}" > /etc/vulkan/icd.d/nvidia_icd.json \
|
||||
# Configure EGL manually
|
||||
&& mkdir -pm755 /usr/share/glvnd/egl_vendor.d/ \
|
||||
&& echo "{\n\
|
||||
\"file_format_version\" : \"1.0.0\",\n\
|
||||
\"ICD\": {\n\
|
||||
\"library_path\": \"libEGL_nvidia.so.0\"\n\
|
||||
}\n\
|
||||
}" > /usr/share/glvnd/egl_vendor.d/10_nvidia.json
|
||||
|
||||
# Expose NVIDIA libraries and paths
|
||||
ENV PATH=/usr/local/nvidia/bin${PATH:+:${PATH}} \
|
||||
LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}/usr/local/nvidia/lib:/usr/local/nvidia/lib64 \
|
||||
XDG_SESSION_TYPE=x11 \
|
||||
# Enable AppImage execution in containers
|
||||
APPIMAGE_EXTRACT_AND_RUN=1
|
||||
|
||||
ENV \
|
||||
# Make all NVIDIA GPUs visible by default
|
||||
NVIDIA_VISIBLE_DEVICES=all \
|
||||
# All NVIDIA driver capabilities should preferably be used, check `NVIDIA_DRIVER_CAPABILITIES` inside the container if things do not work
|
||||
NVIDIA_DRIVER_CAPABILITIES=all \
|
||||
# Disable VSYNC for NVIDIA GPUs
|
||||
__GL_SYNC_TO_VBLANK=0
|
||||
|
||||
COPY .patches /tmp/
|
||||
|
||||
#Build and install gpu-screen-recorder
|
||||
RUN apt-get update -y \
|
||||
&& apt-get install -y \
|
||||
curl \
|
||||
unzip \
|
||||
git \
|
||||
build-essential \
|
||||
ninja-build \
|
||||
gcc \
|
||||
meson \
|
||||
cmake \
|
||||
ccache \
|
||||
bison \
|
||||
software-properties-common \
|
||||
ca-certificates \
|
||||
equivs \
|
||||
ca-certificates\
|
||||
libcap2-bin \
|
||||
libllvm15 \
|
||||
libavcodec-dev \
|
||||
libavformat-dev \
|
||||
libavutil-dev \
|
||||
libavfilter-dev \
|
||||
libavdevice-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libx11-dev \
|
||||
libxcomposite-dev \
|
||||
libkpipewire-dev \
|
||||
libxrandr-dev \
|
||||
libxi-dev \
|
||||
libxdamage-dev \
|
||||
libxfixes-dev \
|
||||
libxi-dev \
|
||||
libxdamage-dev \
|
||||
libpulse-dev \
|
||||
libswresample-dev \
|
||||
libva-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libgl-dev \
|
||||
libegl-dev \
|
||||
libwayland-dev \
|
||||
libnvidia-egl-wayland-dev \
|
||||
libwayland-egl-backend-dev \
|
||||
wayland-protocols \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
#Install Nvrtc
|
||||
&& NVRTC_VERSION="11.0.221" \
|
||||
&& cd /tmp && curl -fsSL -o nvidia_cuda_nvrtc_linux_x86_64.whl "https://developer.download.nvidia.com/compute/redist/nvidia-cuda-nvrtc/nvidia_cuda_nvrtc-${NVRTC_VERSION}-cp36-cp36m-linux_x86_64.whl" \
|
||||
&& unzip -joq -d ./nvrtc nvidia_cuda_nvrtc_linux_x86_64.whl && cd nvrtc && chmod 755 libnvrtc* \
|
||||
&& find . -maxdepth 1 -type f -name "*libnvrtc.so.*" -exec sh -c 'ln -snf $(basename {}) libnvrtc.so' \; \
|
||||
&& mkdir -p /usr/local/nvidia/lib && mv -f libnvrtc* /usr/local/nvidia/lib \
|
||||
&& git clone https://repo.dec05eba.com/gpu-screen-recorder && cd gpu-screen-recorder \
|
||||
&& git apply /tmp/connectcheckskip.patch && git apply /tmp/devicearg.patch \
|
||||
&& meson setup build \
|
||||
&& meson configure --prefix=/usr --buildtype=release -Dsystemd=true -Dstrip=true build \
|
||||
&& ninja -C build install
|
||||
|
||||
# #Try building shadow-cast
|
||||
# RUN git clone https://github.com/gmbeard/shadow-cast && cd shadow-cast \
|
||||
# && mkdir ./build && cd ./build \
|
||||
# && cmake -DCMAKE_CXX_FLAGS="-Wno-error=unused-result" -DCMAKE_C_FLAGS="-Wno-error=unused-result" .. \
|
||||
# && cmake --build . -- -j$(nproc) \
|
||||
# && chmod +x ./install-helper.sh \
|
||||
# && ./install-helper.sh
|
||||
|
||||
RUN apt-get update -y; \
|
||||
apt-get upgrade -y; \
|
||||
add-apt-repository ppa:savoury1/ffmpeg4 \
|
||||
add-apt-repository ppa:savoury1/ffmpeg6 \
|
||||
apt-get update -y; \
|
||||
apt-get upgrade -y && apt-get dist-upgrade -y; \
|
||||
apt-get install ffmpeg -y; \
|
||||
#
|
||||
# Log the ffmpeg version
|
||||
ffmpeg -version
|
||||
|
||||
# Install Xorg and NVIDIA driver installer dependencies
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
kmod \
|
||||
libc6-dev \
|
||||
libc6:i386 \
|
||||
libpci3 \
|
||||
libelf-dev \
|
||||
pkg-config \
|
||||
xorg \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
1
bin/input/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/target
|
||||
1701
bin/input/Cargo.lock
generated
@@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "warp-input"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.82"
|
||||
chrono = "0.4.38"
|
||||
clap = "4.5.4"
|
||||
enigo = "0.2.1"
|
||||
env_logger = "0.11.3"
|
||||
log = "0.4.21"
|
||||
moq-native = { git = "https://github.com/kixelated/moq-rs", version = "0.1.0" }
|
||||
moq-transport = { git = "https://github.com/kixelated/moq-rs", version = "0.5.0" }
|
||||
rand = "0.8.5"
|
||||
serde = { version="1.0.202" , features = ["derive"]}
|
||||
serde_json = "1.0.117"
|
||||
tokio = "1.37.0"
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = "0.3.18"
|
||||
url = "2.5.0"
|
||||
@@ -1,43 +0,0 @@
|
||||
use clap::Parser;
|
||||
use std::{net, path};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
pub struct Config {
|
||||
/// Listen for UDP packets on the given address.
|
||||
#[arg(long, default_value = "[::]:8080")]
|
||||
pub bind: net::SocketAddr,
|
||||
|
||||
/// Connect to the given URL starting with https://
|
||||
#[arg(value_parser = moq_url)]
|
||||
pub url: Url,
|
||||
|
||||
/// Use the TLS root CA at this path, encoded as PEM.
|
||||
///
|
||||
/// This value can be provided multiple times for multiple roots.
|
||||
/// If this is empty, system roots will be used instead
|
||||
#[arg(long)]
|
||||
pub tls_root: Vec<path::PathBuf>,
|
||||
|
||||
/// Danger: Disable TLS certificate verification.
|
||||
///
|
||||
/// Fine for local development, but should be used in caution in production.
|
||||
#[arg(long)]
|
||||
pub tls_disable_verify: bool,
|
||||
|
||||
/// Publish the current time to the relay, otherwise only subscribe.
|
||||
// #[arg(long)]
|
||||
// pub publish: bool,
|
||||
|
||||
/// The name of the input track.
|
||||
#[arg(long, default_value = "netris")]
|
||||
pub namespace: String,
|
||||
|
||||
/// The name of the input track.
|
||||
#[arg(long, default_value = ".catalog")]
|
||||
pub track: String,
|
||||
}
|
||||
|
||||
fn moq_url(s: &str) -> Result<Url, String> {
|
||||
Url::try_from(s).map_err(|e| e.to_string())
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
use anyhow::Context;
|
||||
use enigo::{
|
||||
Axis::Horizontal,
|
||||
Coordinate::Rel,
|
||||
Direction::{Press, Release},
|
||||
Enigo, Keyboard, Mouse, Settings,
|
||||
};
|
||||
use moq_transport::
|
||||
serve::{
|
||||
DatagramsReader, GroupsReader, ObjectsReader,
|
||||
StreamReader, TrackReader, TrackReaderMode,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub struct Subscriber {
|
||||
track: TrackReader,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct MessageObject {
|
||||
input_type: String,
|
||||
delta_y: Option<i32>,
|
||||
delta_x: Option<i32>,
|
||||
button: Option<i32>,
|
||||
key_code: Option<i32>,
|
||||
}
|
||||
|
||||
impl Subscriber {
|
||||
pub fn new(track: TrackReader) -> Self {
|
||||
Self { track }
|
||||
}
|
||||
|
||||
// pub async fn run(self) -> anyhow::Result<()> {
|
||||
// loop {
|
||||
// match self.track.mode().await {
|
||||
// Ok(mode) => match mode {
|
||||
// TrackReaderMode::Stream(stream) => loop {
|
||||
// if let Err(err) = Self::recv_stream(stream.clone()).await {
|
||||
// tracing::warn!("Error receiving streams: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// TrackReaderMode::Groups(groups) => loop {
|
||||
// if let Err(err) = Self::recv_groups(groups.clone()).await {
|
||||
// tracing::warn!("Error receiving groups: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// TrackReaderMode::Objects(objects) => loop {
|
||||
// if let Err(err) = Self::recv_objects(objects.clone()).await {
|
||||
// tracing::warn!("Error receiving objects: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// TrackReaderMode::Datagrams(datagrams) => loop {
|
||||
// if let Err(err) = Self::recv_datagrams(datagrams.clone()).await {
|
||||
// tracing::warn!("Error receiving datagrams: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// Err(_) => {
|
||||
// tracing::warn!("Failed to get mode, retrying...");
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// return Ok(());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
match self.track.mode().await.context("failed to connect")? {
|
||||
TrackReaderMode::Stream(stream) => Self::recv_stream(stream).await,
|
||||
TrackReaderMode::Groups(groups) => Self::recv_groups(groups).await,
|
||||
TrackReaderMode::Objects(objects) => Self::recv_objects(objects).await,
|
||||
TrackReaderMode::Datagrams(datagrams) => Self::recv_datagrams(datagrams).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn recv_stream(mut track: StreamReader) -> anyhow::Result<()> {
|
||||
while let Some(mut group) = track.next().await? {
|
||||
while let Some(object) = group.read_next().await? {
|
||||
let str = String::from_utf8_lossy(&object);
|
||||
println!("{}", str);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn recv_groups(mut groups: GroupsReader) -> anyhow::Result<()> {
|
||||
while let Some(mut group) = groups.next().await? {
|
||||
let base = group
|
||||
.read_next()
|
||||
.await
|
||||
.context("failed to get first object")?
|
||||
.context("empty group")?;
|
||||
|
||||
//TODO: Use this to allow for authorisation (admin, player or guest) etc etc
|
||||
let _base = String::from_utf8_lossy(&base);
|
||||
// let json = serde_json::from_str(&str)?;
|
||||
|
||||
//TODO: Handle clipboard
|
||||
let mut enigo = Enigo::new(&Settings::default()).unwrap();
|
||||
while let Some(object) = group.read_next().await? {
|
||||
let str = String::from_utf8_lossy(&object);
|
||||
let parsed: MessageObject = serde_json::from_str(&str)?;
|
||||
match parsed.input_type.as_str() {
|
||||
"mouse_move" => {
|
||||
if let (Some(x), Some(y)) = (parsed.delta_x, parsed.delta_y) {
|
||||
// println!("Handling mouse_move with delta_x: {}, delta_y: {}", x, y);
|
||||
enigo.move_mouse(x, y, Rel).unwrap();
|
||||
}
|
||||
}
|
||||
"mouse_key_down" => {
|
||||
if let Some(button) = parsed.button {
|
||||
// println!("Handling mouse_key_down with key: {}", button);
|
||||
if let Some(key) = mouse_key_to_enigo(button) {
|
||||
enigo.button(key, Press).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
"mouse_key_up" => {
|
||||
if let Some(button) = parsed.button {
|
||||
// println!("Handling mouse_key_up with key: {}", button);
|
||||
if let Some(key) = mouse_key_to_enigo(button) {
|
||||
enigo.button(key, Release).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
"mouse_wheel_up" => {
|
||||
//TODO: handle vertical scrolling
|
||||
// println!("Handling mouse_wheel_up with key");
|
||||
enigo.scroll(-2, Horizontal).unwrap();
|
||||
}
|
||||
"mouse_wheel_down" => {
|
||||
//TODO: handle vertical scrolling
|
||||
// println!("Handling mouse_wheel_down with key");
|
||||
enigo.scroll(2, Horizontal).unwrap();
|
||||
}
|
||||
"key_up" => {
|
||||
if let Some(key_code) = parsed.key_code {
|
||||
// println!("Handling key_up with key: {}", key_code);
|
||||
if let Some(key) = key_to_enigo(key_code as u8) {
|
||||
enigo.key(key, Release).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
"key_down" => {
|
||||
if let Some(key_code) = parsed.key_code {
|
||||
// println!("Handling key_down with key: {}", key_code);
|
||||
if let Some(key) = key_to_enigo(key_code as u8) {
|
||||
enigo.key(key, Press).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown input_type: {}", parsed.input_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn recv_objects(mut objects: ObjectsReader) -> anyhow::Result<()> {
|
||||
while let Some(mut object) = objects.next().await? {
|
||||
let payload = object.read_all().await?;
|
||||
let str = String::from_utf8_lossy(&payload);
|
||||
println!("{}", str);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn recv_datagrams(mut datagrams: DatagramsReader) -> anyhow::Result<()> {
|
||||
while let Some(datagram) = datagrams.read().await? {
|
||||
let str = String::from_utf8_lossy(&datagram.payload);
|
||||
println!("{}", str);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_key_to_enigo(key: i32) -> Option<enigo::Button> {
|
||||
match key {
|
||||
0 => Some(enigo::Button::Left),
|
||||
1 => Some(enigo::Button::Middle),
|
||||
2 => Some(enigo::Button::Right),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_to_enigo(key: u8) -> Option<enigo::Key> {
|
||||
match key {
|
||||
27 => Some(enigo::Key::Escape),
|
||||
112 => Some(enigo::Key::F1),
|
||||
113 => Some(enigo::Key::F2),
|
||||
114 => Some(enigo::Key::F3),
|
||||
115 => Some(enigo::Key::F4),
|
||||
116 => Some(enigo::Key::F5),
|
||||
117 => Some(enigo::Key::F6),
|
||||
118 => Some(enigo::Key::F7),
|
||||
119 => Some(enigo::Key::F8),
|
||||
120 => Some(enigo::Key::F9),
|
||||
121 => Some(enigo::Key::F10),
|
||||
122 => Some(enigo::Key::F11),
|
||||
123 => Some(enigo::Key::F12),
|
||||
// 19 => Some(enigo::Key::Pause), // Pause
|
||||
// 97 => Some(enigo::Key::Print), // Print
|
||||
46 => Some(enigo::Key::Delete),
|
||||
35 => Some(enigo::Key::End),
|
||||
192 => Some(enigo::Key::Unicode('`')),
|
||||
48 => Some(enigo::Key::Unicode('0')),
|
||||
49 => Some(enigo::Key::Unicode('1')),
|
||||
50 => Some(enigo::Key::Unicode('2')),
|
||||
51 => Some(enigo::Key::Unicode('3')),
|
||||
52 => Some(enigo::Key::Unicode('4')),
|
||||
53 => Some(enigo::Key::Unicode('5')),
|
||||
54 => Some(enigo::Key::Unicode('6')),
|
||||
55 => Some(enigo::Key::Unicode('7')),
|
||||
56 => Some(enigo::Key::Unicode('8')),
|
||||
57 => Some(enigo::Key::Unicode('9')),
|
||||
189 => Some(enigo::Key::Unicode('-')),
|
||||
187 => Some(enigo::Key::Unicode('=')),
|
||||
8 => Some(enigo::Key::Backspace),
|
||||
9 => Some(enigo::Key::Tab),
|
||||
219 => Some(enigo::Key::Unicode('[')),
|
||||
221 => Some(enigo::Key::Unicode(']')),
|
||||
220 => Some(enigo::Key::Unicode('\\')),
|
||||
20 => Some(enigo::Key::CapsLock),
|
||||
186 => Some(enigo::Key::Unicode(';')),
|
||||
222 => Some(enigo::Key::Unicode('\'')),
|
||||
13 => Some(enigo::Key::Return),
|
||||
16 => Some(enigo::Key::Shift), // ShiftL
|
||||
188 => Some(enigo::Key::Unicode(',')),
|
||||
190 => Some(enigo::Key::Unicode('.')),
|
||||
191 => Some(enigo::Key::Unicode('/')),
|
||||
161 => Some(enigo::Key::Shift), // ShiftR
|
||||
38 => Some(enigo::Key::UpArrow),
|
||||
17 => Some(enigo::Key::Control), // ControlL
|
||||
18 => Some(enigo::Key::Alt), // AltL
|
||||
32 => Some(enigo::Key::Space),
|
||||
165 => Some(enigo::Key::Alt), // AltR
|
||||
// 103 => Some(enigo::Key::Menu),
|
||||
163 => Some(enigo::Key::Control), // ControlR
|
||||
37 => Some(enigo::Key::LeftArrow),
|
||||
40 => Some(enigo::Key::DownArrow),
|
||||
39 => Some(enigo::Key::RightArrow),
|
||||
// 99 => Some(enigo::Key::Raw(45)), // Insert
|
||||
34 => Some(enigo::Key::PageDown),
|
||||
36 => Some(enigo::Key::Home),
|
||||
33 => Some(enigo::Key::PageUp),
|
||||
a if a >= 65 && a <= 90 => Some(enigo::Key::Unicode((a - 65 + ('a' as u8)) as char)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
//NAME="${NAME:-$(head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16)}"
|
||||
// let _name = env::var("NAMESPACE").unwrap_or_else(|_| {
|
||||
// let rng = rand::thread_rng();
|
||||
// let random_string: String = rng
|
||||
// .sample_iter(&rand::distributions::Alphanumeric)
|
||||
// .take(16)
|
||||
// .map(char::from)
|
||||
// .collect();
|
||||
// random_string
|
||||
// });
|
||||
@@ -1,121 +0,0 @@
|
||||
use anyhow::Context;
|
||||
use chrono::prelude::*;
|
||||
use clap::Parser;
|
||||
use moq_native::quic;
|
||||
use moq_transport::{serve, session::Subscriber};
|
||||
use std::net;
|
||||
use url::Url;
|
||||
|
||||
mod input;
|
||||
|
||||
#[derive(Parser, Clone)]
|
||||
pub struct Cli {
|
||||
/// Listen for UDP packets on the given address.
|
||||
#[arg(long, default_value = "[::]:0")]
|
||||
pub bind: net::SocketAddr,
|
||||
|
||||
/// Connect to the given URL starting with https://
|
||||
#[arg()]
|
||||
pub url: Url,
|
||||
|
||||
/// The TLS configuration.
|
||||
#[command(flatten)]
|
||||
pub tls: moq_native::tls::Cli,
|
||||
|
||||
// /// Publish the current time to the relay, otherwise only subscribe.
|
||||
// #[arg(long)]
|
||||
// pub publish: bool,
|
||||
/// The name of the input track.
|
||||
#[arg(long, default_value = "netris")]
|
||||
pub namespace: String,
|
||||
|
||||
/// The name of the input track.
|
||||
#[arg(long, default_value = ".catalog")]
|
||||
pub track: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
// Disable tracing so we don't get a bunch of Quinn spam.
|
||||
let tracer = tracing_subscriber::FmtSubscriber::builder()
|
||||
.with_max_level(tracing::Level::WARN)
|
||||
.finish();
|
||||
tracing::subscriber::set_global_default(tracer).unwrap();
|
||||
|
||||
let config = Cli::parse();
|
||||
let tls = config.tls.load()?;
|
||||
|
||||
let quic = quic::Endpoint::new(quic::Config {
|
||||
bind: config.bind,
|
||||
tls,
|
||||
})?;
|
||||
|
||||
let start = Utc::now();
|
||||
let mut now = start;
|
||||
|
||||
loop {
|
||||
log::info!("connecting to server: url={}", config.url);
|
||||
|
||||
let session = quic.client.connect(&config.url).await?;
|
||||
|
||||
let (session, mut subscriber) = Subscriber::connect(session)
|
||||
.await
|
||||
.context("failed to create MoQ Transport session")?;
|
||||
|
||||
let namespace = format!("{}input", config.namespace);
|
||||
|
||||
let (prod, sub) = serve::Track::new(namespace, config.track.clone()).produce();
|
||||
|
||||
let input = input::Subscriber::new(sub);
|
||||
|
||||
// let (session, mut publisher) = Publisher::connect(session)
|
||||
// .await
|
||||
// .context("failed to create MoQ Transport session")?;
|
||||
|
||||
// let (mut writer, _, reader) = serve::Tracks {
|
||||
// namespace: config.namespace.clone(),
|
||||
// }
|
||||
// .produce();
|
||||
|
||||
// let track = writer.create(&config.track).unwrap();
|
||||
// let input_publisher = input::Publisher::new(track.groups()?);
|
||||
|
||||
tokio::select! {
|
||||
res = session.run() => {
|
||||
if let Err(e) = res {
|
||||
log::error!("session error: {}", e);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
res = input.run() => {
|
||||
if let Err(e) = res {
|
||||
log::error!("input subscriber error: {}", e);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
// res = publisher.announce(reader) => res.context("failed to serve tracks")?,
|
||||
res = subscriber.subscribe(prod) => {
|
||||
if let Err(e) = res {
|
||||
log::error!("failed to subscribe to track: {}", e);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let next = now + chrono::Duration::try_minutes(1).unwrap();
|
||||
let next = next.with_second(0).unwrap().with_nanosecond(0).unwrap();
|
||||
|
||||
let delay = (next - now).to_std().unwrap();
|
||||
tokio::time::sleep(delay).await;
|
||||
|
||||
// if next.minute() - now.minute() == 10 {
|
||||
// return Ok(());
|
||||
// }
|
||||
|
||||
now = next; // just assume we didn't undersleep
|
||||
}
|
||||
|
||||
// Ok(())
|
||||
}
|
||||
1
cli
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
docker build -t server -f server.Dockerfile .
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
cargo run -- --namespace $SESSION_ID --bind "[::]:8080" https://fst.so:4443
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
NAME="${NAME:-$(head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16)}"
|
||||
|
||||
# docker run --gpus all --device=/dev/dri --rm -it --entrypoint /bin/bash -e SESSION_ID=G4r06Kc8vDmwIXPG -v "$(pwd)":/game -p 8080:8080/udp --cap-add=SYS_NICE --cap-add=SYS_ADMIN server
|
||||
docker run --gpus all --device=/dev/dri --rm -it --entrypoint /bin/bash -e SESSION_ID=$NAME -v "$(pwd)":/game -p 8080:8080/udp --cap-add=SYS_NICE --cap-add=SYS_ADMIN server
|
||||
@@ -1,20 +0,0 @@
|
||||
#This fixes the error where x11-apps in docker cannot seem to access the hosts DISPLAY server
|
||||
# Error: No protocol specified
|
||||
# Error: Can't open display: :10.0
|
||||
#https://askubuntu.com/a/1470341 //Run it on host OS
|
||||
xhost +Local:*
|
||||
xhost
|
||||
|
||||
#Fun fact Weston won't run if you do not have Wayland running on the host (i have yet to try running with Xwayland inside the container)
|
||||
#Run weston using your host's X11 display server
|
||||
weston --backend=x11-backend.so
|
||||
|
||||
#Run inside the terminal of the weston you just created... cool right?
|
||||
weston --backend=wayland-backend.so
|
||||
|
||||
#Run
|
||||
docker run --gpus all --entrypoint /bin/bash --rm -it -v $(pwd):/games -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY --cap-add=SYS_NICE --cap-add=SYS_ADMIN recorder
|
||||
|
||||
docker run --gpus all --entrypoint /bin/bash --device=/dev/dri --rm -it -v $(pwd):/game --cap-add=SYS_NICE --cap-add=SYS_ADMIN ghcr.io/wanjohiryan/netris/server:nightly
|
||||
|
||||
ffmpeg -hide_banner -v quiet -stream_loop -1 -re -i /game/test.mp4 -an -f mp4 -movflags empty_moov+frag_every_frame+separate_moof+omit_tfhd_offset - | RUST_LOG=moq_pub=info warp --name "netris" https://fst.so:4443
|
||||
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "nestri",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "turbo build",
|
||||
"dev": "turbo dev",
|
||||
"lint": "turbo lint",
|
||||
"format": "prettier --write \"**/*.{ts,tsx,md}\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.2.5",
|
||||
"turbo": "^2.0.14",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"packageManager": "bun@1.1.18",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
]
|
||||
}
|
||||
3
packages/eslint-config/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# `@turbo/eslint-config`
|
||||
|
||||
Collection of internal eslint configurations.
|
||||
34
packages/eslint-config/library.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { resolve } = require("node:path");
|
||||
|
||||
const project = resolve(process.cwd(), "tsconfig.json");
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
extends: ["eslint:recommended", "prettier", "turbo"],
|
||||
plugins: ["only-warn"],
|
||||
globals: {
|
||||
React: true,
|
||||
JSX: true,
|
||||
},
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project,
|
||||
},
|
||||
},
|
||||
},
|
||||
ignorePatterns: [
|
||||
// Ignore dotfiles
|
||||
".*.js",
|
||||
"node_modules/",
|
||||
"dist/",
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.js?(x)", "*.ts?(x)"],
|
||||
},
|
||||
],
|
||||
};
|
||||
35
packages/eslint-config/next.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const { resolve } = require("node:path");
|
||||
|
||||
const project = resolve(process.cwd(), "tsconfig.json");
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"prettier",
|
||||
require.resolve("@vercel/style-guide/eslint/next"),
|
||||
"turbo",
|
||||
],
|
||||
globals: {
|
||||
React: true,
|
||||
JSX: true,
|
||||
},
|
||||
env: {
|
||||
node: true,
|
||||
browser: true,
|
||||
},
|
||||
plugins: ["only-warn"],
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project,
|
||||
},
|
||||
},
|
||||
},
|
||||
ignorePatterns: [
|
||||
// Ignore dotfiles
|
||||
".*.js",
|
||||
"node_modules/",
|
||||
],
|
||||
overrides: [{ files: ["*.js?(x)", "*.ts?(x)"] }],
|
||||
};
|
||||
19
packages/eslint-config/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "@nestri/eslint-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"files": [
|
||||
"library.js",
|
||||
"next.js",
|
||||
"react-internal.js"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@vercel/style-guide": "^5.2.0",
|
||||
"eslint-config-turbo": "^2.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-only-warn": "^1.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
39
packages/eslint-config/react-internal.js
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
const { resolve } = require("node:path");
|
||||
|
||||
const project = resolve(process.cwd(), "tsconfig.json");
|
||||
|
||||
/*
|
||||
* This is a custom ESLint configuration for use with
|
||||
* internal (bundled by their consumer) libraries
|
||||
* that utilize React.
|
||||
*/
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
extends: ["eslint:recommended", "prettier", "turbo"],
|
||||
plugins: ["only-warn"],
|
||||
globals: {
|
||||
React: true,
|
||||
JSX: true,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project,
|
||||
},
|
||||
},
|
||||
},
|
||||
ignorePatterns: [
|
||||
// Ignore dotfiles
|
||||
".*.js",
|
||||
"node_modules/",
|
||||
"dist/",
|
||||
],
|
||||
overrides: [
|
||||
// Force ESLint to detect .tsx files
|
||||
{ files: ["*.js?(x)", "*.ts?(x)"] },
|
||||
],
|
||||
};
|
||||
20
packages/typescript-config/base.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Default",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true,
|
||||
"incremental": false,
|
||||
"isolatedModules": true,
|
||||
"lib": ["es2022", "DOM", "DOM.Iterable"],
|
||||
"module": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"moduleResolution": "NodeNext",
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "ES2022"
|
||||
}
|
||||
}
|
||||
13
packages/typescript-config/nextjs.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Next.js",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"plugins": [{ "name": "next" }],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowJs": true,
|
||||
"jsx": "preserve",
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
9
packages/typescript-config/package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@nestri/typescript-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
8
packages/typescript-config/react-library.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "React Library",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
||||
10
packages/ui/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@nestri/eslint-config/react-internal.js"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: "./tsconfig.lint.json",
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
};
|
||||
28
packages/ui/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@nestri/ui",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./button": "./src/button.tsx",
|
||||
"./card": "./src/card.tsx",
|
||||
"./code": "./src/code.tsx"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint . --max-warnings 0",
|
||||
"generate:component": "turbo gen react-component"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestri/eslint-config": "*",
|
||||
"@nestri/typescript-config": "*",
|
||||
"@turbo/gen": "^1.12.4",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/eslint": "^8.56.5",
|
||||
"@types/react": "^18.2.61",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"eslint": "^8.57.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
}
|
||||
20
packages/ui/src/button.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
|
||||
interface ButtonProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
appName: string;
|
||||
}
|
||||
|
||||
export const Button = ({ children, className, appName }: ButtonProps) => {
|
||||
return (
|
||||
<button
|
||||
className={className}
|
||||
onClick={() => alert(`Hello from your ${appName} app!`)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||