@zenithbuild/core 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +24 -40
- package/bin/zen-build.ts +2 -0
- package/bin/zen-dev.ts +2 -0
- package/bin/zen-preview.ts +2 -0
- package/bin/zenith.ts +2 -0
- package/cli/commands/add.ts +37 -0
- package/cli/commands/build.ts +37 -0
- package/cli/commands/create.ts +702 -0
- package/cli/commands/dev.ts +197 -0
- package/cli/commands/index.ts +112 -0
- package/cli/commands/preview.ts +62 -0
- package/cli/commands/remove.ts +33 -0
- package/cli/index.ts +10 -0
- package/cli/main.ts +101 -0
- package/cli/utils/branding.ts +153 -0
- package/cli/utils/logger.ts +40 -0
- package/cli/utils/plugin-manager.ts +114 -0
- package/cli/utils/project.ts +71 -0
- package/compiler/build-analyzer.ts +122 -0
- package/compiler/discovery/layouts.ts +61 -0
- package/compiler/index.ts +40 -24
- package/compiler/ir/types.ts +1 -0
- package/compiler/parse/parseScript.ts +29 -5
- package/compiler/parse/parseTemplate.ts +96 -58
- package/compiler/parse/scriptAnalysis.ts +77 -0
- package/compiler/runtime/dataExposure.ts +49 -31
- package/compiler/runtime/generateDOM.ts +18 -17
- package/compiler/runtime/generateHydrationBundle.ts +24 -5
- package/compiler/runtime/transformIR.ts +140 -49
- package/compiler/runtime/wrapExpressionWithLoop.ts +11 -11
- package/compiler/spa-build.ts +70 -153
- package/compiler/ssg-build.ts +412 -0
- package/compiler/transform/layoutProcessor.ts +132 -0
- package/compiler/transform/transformNode.ts +19 -19
- package/dist/cli.js +11648 -0
- package/dist/zen-build.js +11659 -0
- package/dist/zen-dev.js +11659 -0
- package/dist/zen-preview.js +11659 -0
- package/dist/zenith.js +11659 -0
- package/package.json +22 -2
- package/runtime/bundle-generator.ts +416 -0
- package/runtime/client-runtime.ts +532 -0
- package/.eslintignore +0 -15
- package/.gitattributes +0 -2
- package/.github/ISSUE_TEMPLATE/compiler-errors-for-invalid-state-declarations.md +0 -25
- package/.github/ISSUE_TEMPLATE/new_ticket.yaml +0 -34
- package/.github/pull_request_template.md +0 -15
- package/.github/workflows/discord-changelog.yml +0 -141
- package/.github/workflows/discord-notify.yml +0 -242
- package/.github/workflows/discord-version.yml +0 -195
- package/.prettierignore +0 -13
- package/.prettierrc +0 -21
- package/.zen.d.ts +0 -15
- package/app/components/Button.zen +0 -46
- package/app/components/Link.zen +0 -11
- package/app/favicon.ico +0 -0
- package/app/layouts/Main.zen +0 -59
- package/app/pages/about.zen +0 -23
- package/app/pages/blog/[id].zen +0 -53
- package/app/pages/blog/index.zen +0 -32
- package/app/pages/dynamic-dx.zen +0 -712
- package/app/pages/dynamic-primitives.zen +0 -453
- package/app/pages/index.zen +0 -154
- package/app/pages/navigation-demo.zen +0 -229
- package/app/pages/posts/[...slug].zen +0 -61
- package/app/pages/primitives-demo.zen +0 -273
- package/assets/logos/0E3B5DDD-605C-4839-BB2E-DFCA8ADC9604.PNG +0 -0
- package/assets/logos/760971E5-79A1-44F9-90B9-925DF30F4278.PNG +0 -0
- package/assets/logos/8A06ED80-9ED2-4689-BCBD-13B2E95EE8E4.JPG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.PNG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.svg +0 -601
- package/assets/logos/README.md +0 -54
- package/assets/logos/zen.icns +0 -0
- package/bun.lock +0 -39
- package/compiler/legacy/binding.ts +0 -254
- package/compiler/legacy/bindings.ts +0 -338
- package/compiler/legacy/component-process.ts +0 -1208
- package/compiler/legacy/component.ts +0 -301
- package/compiler/legacy/event.ts +0 -50
- package/compiler/legacy/expression.ts +0 -1149
- package/compiler/legacy/mutation.ts +0 -280
- package/compiler/legacy/parse.ts +0 -299
- package/compiler/legacy/split.ts +0 -608
- package/compiler/legacy/types.ts +0 -32
- package/docs/COMMENTS.md +0 -111
- package/docs/COMMITS.md +0 -36
- package/docs/CONTRIBUTING.md +0 -116
- package/docs/STYLEGUIDE.md +0 -62
- package/scripts/webhook-proxy.ts +0 -213
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
name: Discord Changelog Notifications
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
types: [closed]
|
|
9
|
-
|
|
10
|
-
# Security: Limit permissions to only what's needed
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
pull-requests: read
|
|
14
|
-
|
|
15
|
-
jobs:
|
|
16
|
-
notify:
|
|
17
|
-
runs-on: ubuntu-latest
|
|
18
|
-
steps:
|
|
19
|
-
- name: Send Changelog to Discord
|
|
20
|
-
env:
|
|
21
|
-
DISCORD_CHANGELOG_WEBHOOK_URL: ${{ secrets.DISCORD_CHANGELOG_WEBHOOK_URL }}
|
|
22
|
-
run: |
|
|
23
|
-
set -e # Exit on error
|
|
24
|
-
set +x # Don't echo commands (prevents secret exposure in logs)
|
|
25
|
-
|
|
26
|
-
# Mask the webhook URL in logs to prevent accidental exposure
|
|
27
|
-
echo "::add-mask::$DISCORD_CHANGELOG_WEBHOOK_URL"
|
|
28
|
-
|
|
29
|
-
# Validate secret is set
|
|
30
|
-
if [ -z "$DISCORD_CHANGELOG_WEBHOOK_URL" ]; then
|
|
31
|
-
echo "❌ DISCORD_CHANGELOG_WEBHOOK_URL secret is not set"
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
# Validate webhook URL format for security
|
|
36
|
-
if [[ ! "$DISCORD_CHANGELOG_WEBHOOK_URL" =~ ^https://discord\.com/api/webhooks/[0-9]+/[A-Za-z0-9_-]+$ ]]; then
|
|
37
|
-
echo "❌ Invalid Discord webhook URL format"
|
|
38
|
-
exit 1
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
# Determine event type and get data
|
|
42
|
-
if [ "${{ github.event_name }}" = "push" ]; then
|
|
43
|
-
EVENT_TYPE="push"
|
|
44
|
-
BRANCH="${{ github.ref_name }}"
|
|
45
|
-
PUSHER="${{ github.event.pusher.name }}"
|
|
46
|
-
COMPARE_URL="${{ github.event.compare }}"
|
|
47
|
-
|
|
48
|
-
# Get commit messages and count
|
|
49
|
-
COMMITS_JSON='${{ toJSON(github.event.commits) }}'
|
|
50
|
-
COMMITS=$(echo "$COMMITS_JSON" | jq -r '.[] | "- " + (.message | split("\n")[0])' | head -10)
|
|
51
|
-
COMMITS_COUNT=$(echo "$COMMITS_JSON" | jq 'length')
|
|
52
|
-
|
|
53
|
-
COLOR="3447003" # Blue
|
|
54
|
-
EMOJI="📦"
|
|
55
|
-
TITLE="Code Pushed"
|
|
56
|
-
# Escape backticks for shell variable
|
|
57
|
-
BRANCH_ESC=$(echo "$BRANCH" | sed "s/\\\`/\\\\\\\`/g")
|
|
58
|
-
DESCRIPTION="**$COMMITS_COUNT commit(s)** pushed to branch \`$BRANCH_ESC\` by $PUSHER"
|
|
59
|
-
|
|
60
|
-
elif [ "${{ github.event.pull_request.merged }}" = "true" ]; then
|
|
61
|
-
EVENT_TYPE="merge"
|
|
62
|
-
PR_NUMBER="${{ github.event.pull_request.number }}"
|
|
63
|
-
PR_TITLE="${{ github.event.pull_request.title }}"
|
|
64
|
-
PR_AUTHOR="${{ github.event.pull_request.user.login }}"
|
|
65
|
-
PR_URL="${{ github.event.pull_request.html_url }}"
|
|
66
|
-
BASE_BRANCH="${{ github.event.pull_request.base.ref }}"
|
|
67
|
-
HEAD_BRANCH="${{ github.event.pull_request.head.ref }}"
|
|
68
|
-
|
|
69
|
-
COLOR="3066993" # Green
|
|
70
|
-
EMOJI="🔀"
|
|
71
|
-
TITLE="Pull Request Merged"
|
|
72
|
-
# Escape backticks and newlines
|
|
73
|
-
HEAD_BRANCH_ESC=$(echo "$HEAD_BRANCH" | sed "s/\\\`/\\\\\\\`/g")
|
|
74
|
-
BASE_BRANCH_ESC=$(echo "$BASE_BRANCH" | sed "s/\\\`/\\\\\\\`/g")
|
|
75
|
-
PR_TITLE_ESC=$(echo "$PR_TITLE" | sed "s/\\\`/\\\\\\\`/g" | sed 's/$/\\n/' | tr -d '\n' | sed 's/\\n$//')
|
|
76
|
-
DESCRIPTION="**PR #$PR_NUMBER**: $PR_TITLE_ESC\nMerged \`$HEAD_BRANCH_ESC\` → \`$BASE_BRANCH_ESC\` by $PR_AUTHOR"
|
|
77
|
-
COMPARE_URL="$PR_URL"
|
|
78
|
-
COMMITS=""
|
|
79
|
-
else
|
|
80
|
-
echo "⏭️ PR not merged, skipping..."
|
|
81
|
-
exit 0
|
|
82
|
-
fi
|
|
83
|
-
|
|
84
|
-
# Export variables for Node.js script
|
|
85
|
-
export EMOJI TITLE COLOR
|
|
86
|
-
|
|
87
|
-
# Use Node.js to properly build JSON payload with escaping
|
|
88
|
-
cat > /tmp/discord_changelog_payload.js <<JS_EOF
|
|
89
|
-
const repo = "${{ github.repository }}";
|
|
90
|
-
const emoji = process.env.EMOJI || '📦';
|
|
91
|
-
const title = process.env.TITLE || 'Code Updated';
|
|
92
|
-
const color = parseInt(process.env.COLOR || '3447003', 10);
|
|
93
|
-
const description = '$DESCRIPTION';
|
|
94
|
-
const compareUrl = '$COMPARE_URL';
|
|
95
|
-
const commits = '$COMMITS';
|
|
96
|
-
|
|
97
|
-
// Build embed
|
|
98
|
-
const embed = {
|
|
99
|
-
title: emoji + ' ' + title,
|
|
100
|
-
description: description,
|
|
101
|
-
url: compareUrl || 'https://github.com/' + repo,
|
|
102
|
-
color: color,
|
|
103
|
-
fields: commits && commits.length > 0 ? [
|
|
104
|
-
{
|
|
105
|
-
name: 'Recent Commits',
|
|
106
|
-
value: commits.length > 1000 ? commits.substring(0, 1000) + '...' : commits,
|
|
107
|
-
inline: false
|
|
108
|
-
}
|
|
109
|
-
] : [],
|
|
110
|
-
footer: {
|
|
111
|
-
text: repo
|
|
112
|
-
},
|
|
113
|
-
timestamp: new Date().toISOString()
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
console.log(JSON.stringify({ embeds: [embed] }));
|
|
117
|
-
JS_EOF
|
|
118
|
-
|
|
119
|
-
# Run the Node.js script
|
|
120
|
-
PAYLOAD=$(node /tmp/discord_changelog_payload.js)
|
|
121
|
-
|
|
122
|
-
# Send to Discord with error handling
|
|
123
|
-
HTTP_CODE=$(curl -s -o /tmp/discord_response.txt -w "%{http_code}" \
|
|
124
|
-
-X POST "$DISCORD_CHANGELOG_WEBHOOK_URL" \
|
|
125
|
-
-H "Content-Type: application/json" \
|
|
126
|
-
-d "$PAYLOAD")
|
|
127
|
-
|
|
128
|
-
# Check response
|
|
129
|
-
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
130
|
-
echo "✅ Successfully sent changelog notification to Discord"
|
|
131
|
-
else
|
|
132
|
-
echo "❌ Failed to send notification (HTTP $HTTP_CODE)"
|
|
133
|
-
if [ -f /tmp/discord_response.txt ]; then
|
|
134
|
-
echo "Response: $(cat /tmp/discord_response.txt)"
|
|
135
|
-
fi
|
|
136
|
-
exit 1
|
|
137
|
-
fi
|
|
138
|
-
|
|
139
|
-
# Clean up
|
|
140
|
-
rm -f /tmp/discord_response.txt /tmp/discord_changelog_payload.js
|
|
141
|
-
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
name: Discord Issue Notifications
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
issues:
|
|
5
|
-
types: [opened, closed, reopened, edited, assigned, unassigned, labeled, unlabeled]
|
|
6
|
-
issue_comment:
|
|
7
|
-
types: [created]
|
|
8
|
-
|
|
9
|
-
# Security: Limit permissions to only what's needed
|
|
10
|
-
permissions:
|
|
11
|
-
issues: write # Needed to add labels to track notified issues
|
|
12
|
-
contents: read
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
notify:
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
steps:
|
|
18
|
-
- name: Send to Discord
|
|
19
|
-
env:
|
|
20
|
-
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
21
|
-
run: |
|
|
22
|
-
set -e # Exit on error
|
|
23
|
-
set +x # Don't echo commands (prevents secret exposure in logs)
|
|
24
|
-
|
|
25
|
-
# Mask the webhook URL in logs to prevent accidental exposure
|
|
26
|
-
echo "::add-mask::$DISCORD_WEBHOOK_URL"
|
|
27
|
-
|
|
28
|
-
# Validate secret is set
|
|
29
|
-
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
|
|
30
|
-
echo "❌ DISCORD_WEBHOOK_URL secret is not set"
|
|
31
|
-
exit 1
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
# Validate webhook URL format for security
|
|
35
|
-
if [[ ! "$DISCORD_WEBHOOK_URL" =~ ^https://discord\.com/api/webhooks/[0-9]+/[A-Za-z0-9_-]+$ ]]; then
|
|
36
|
-
echo "❌ Invalid Discord webhook URL format"
|
|
37
|
-
exit 1
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
# Get issue number and check if already notified
|
|
41
|
-
ISSUE_NUMBER="${{ github.event.issue.number }}"
|
|
42
|
-
REPO="${{ github.repository }}"
|
|
43
|
-
TRACKING_LABEL="discord-notified"
|
|
44
|
-
ACTION="${{ github.event.action }}"
|
|
45
|
-
|
|
46
|
-
# Check if issue already has the tracking label (already notified)
|
|
47
|
-
HAS_LABEL=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json labels --jq ".labels[] | select(.name == \"$TRACKING_LABEL\") | .name" 2>/dev/null || echo "")
|
|
48
|
-
|
|
49
|
-
# Prevent duplicates based on event type
|
|
50
|
-
case "$ACTION" in
|
|
51
|
-
opened)
|
|
52
|
-
# For new issues, skip if already notified
|
|
53
|
-
if [ -n "$HAS_LABEL" ]; then
|
|
54
|
-
echo "⏭️ Issue #$ISSUE_NUMBER already notified to Discord, skipping..."
|
|
55
|
-
exit 0
|
|
56
|
-
fi
|
|
57
|
-
;;
|
|
58
|
-
edited)
|
|
59
|
-
# For edits: if not notified yet, treat as initial notification (for backfilling)
|
|
60
|
-
# If already notified, send update notification
|
|
61
|
-
if [ -z "$HAS_LABEL" ]; then
|
|
62
|
-
echo "ℹ️ Issue #$ISSUE_NUMBER hasn't been initially notified yet, treating edit as initial notification..."
|
|
63
|
-
# Change action to "opened" for initial notification formatting
|
|
64
|
-
ACTION="opened"
|
|
65
|
-
fi
|
|
66
|
-
;;
|
|
67
|
-
labeled|unlabeled)
|
|
68
|
-
# For label changes: if not notified yet, treat as initial notification (for backfilling)
|
|
69
|
-
# If already notified, send update notification
|
|
70
|
-
if [ -z "$HAS_LABEL" ]; then
|
|
71
|
-
echo "ℹ️ Issue #$ISSUE_NUMBER hasn't been initially notified yet, treating label change as initial notification..."
|
|
72
|
-
# Change action to "opened" for initial notification formatting
|
|
73
|
-
ACTION="opened"
|
|
74
|
-
fi
|
|
75
|
-
;;
|
|
76
|
-
assigned|unassigned)
|
|
77
|
-
# For assignment changes, only send if issue was already notified (initial notification sent)
|
|
78
|
-
if [ -z "$HAS_LABEL" ]; then
|
|
79
|
-
echo "⏭️ Issue #$ISSUE_NUMBER hasn't been initially notified yet, skipping assignment notification..."
|
|
80
|
-
exit 0
|
|
81
|
-
fi
|
|
82
|
-
;;
|
|
83
|
-
closed|reopened)
|
|
84
|
-
# Always send for state changes (closed/reopened) - these are important
|
|
85
|
-
# But skip if issue was never initially notified
|
|
86
|
-
if [ -z "$HAS_LABEL" ]; then
|
|
87
|
-
echo "⏭️ Issue #$ISSUE_NUMBER hasn't been initially notified yet, skipping state change notification..."
|
|
88
|
-
exit 0
|
|
89
|
-
fi
|
|
90
|
-
;;
|
|
91
|
-
esac
|
|
92
|
-
|
|
93
|
-
# Determine color, emoji, and title based on action (ACTION already set above)
|
|
94
|
-
case "$ACTION" in
|
|
95
|
-
opened)
|
|
96
|
-
COLOR="3066993" # Green
|
|
97
|
-
EMOJI="📝"
|
|
98
|
-
TITLE="New Issue Created"
|
|
99
|
-
;;
|
|
100
|
-
closed)
|
|
101
|
-
COLOR="15158332" # Red
|
|
102
|
-
EMOJI="✅"
|
|
103
|
-
TITLE="Issue Closed"
|
|
104
|
-
;;
|
|
105
|
-
reopened)
|
|
106
|
-
COLOR="15105570" # Orange
|
|
107
|
-
EMOJI="🔄"
|
|
108
|
-
TITLE="Issue Reopened"
|
|
109
|
-
;;
|
|
110
|
-
edited)
|
|
111
|
-
COLOR="3447003" # Blue
|
|
112
|
-
EMOJI="✏️"
|
|
113
|
-
TITLE="Issue Edited"
|
|
114
|
-
;;
|
|
115
|
-
assigned|unassigned)
|
|
116
|
-
COLOR="10181046" # Purple
|
|
117
|
-
EMOJI="👤"
|
|
118
|
-
TITLE="Issue Assignment Changed"
|
|
119
|
-
;;
|
|
120
|
-
labeled|unlabeled)
|
|
121
|
-
COLOR="15844367" # Gold
|
|
122
|
-
EMOJI="🏷️"
|
|
123
|
-
TITLE="Issue Label Changed"
|
|
124
|
-
;;
|
|
125
|
-
*)
|
|
126
|
-
COLOR="3447003" # Blue
|
|
127
|
-
EMOJI="📋"
|
|
128
|
-
TITLE="Issue Updated"
|
|
129
|
-
;;
|
|
130
|
-
esac
|
|
131
|
-
|
|
132
|
-
# Export variables for Node.js script
|
|
133
|
-
export EMOJI TITLE COLOR
|
|
134
|
-
|
|
135
|
-
# Use Node.js to properly build JSON payload with escaping
|
|
136
|
-
# Write Node.js script to temp file (no quotes on heredoc to allow GitHub Actions expansion)
|
|
137
|
-
cat > /tmp/discord_payload.js <<JS_EOF
|
|
138
|
-
const issue = ${{ toJSON(github.event.issue) }};
|
|
139
|
-
const repo = "${{ github.repository }}";
|
|
140
|
-
const emoji = process.env.EMOJI || '📋';
|
|
141
|
-
const title = process.env.TITLE || 'Issue Updated';
|
|
142
|
-
const color = parseInt(process.env.COLOR || '3447003', 10);
|
|
143
|
-
|
|
144
|
-
// Format labels - use string concatenation to avoid template literal issues
|
|
145
|
-
const labels = issue.labels && issue.labels.length > 0
|
|
146
|
-
? issue.labels.map(function(l) { return String.fromCharCode(96) + l.name + String.fromCharCode(96); }).join(' ')
|
|
147
|
-
: '*No labels*';
|
|
148
|
-
|
|
149
|
-
// Truncate body
|
|
150
|
-
let body = issue.body || '*No description*';
|
|
151
|
-
if (body.length > 1000) {
|
|
152
|
-
body = body.substring(0, 1000) + '...';
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Build embed
|
|
156
|
-
const embed = {
|
|
157
|
-
title: emoji + ' ' + title,
|
|
158
|
-
description: '**' + issue.title + '**',
|
|
159
|
-
url: issue.html_url,
|
|
160
|
-
color: color,
|
|
161
|
-
fields: [
|
|
162
|
-
{
|
|
163
|
-
name: 'Issue #',
|
|
164
|
-
value: '#' + issue.number,
|
|
165
|
-
inline: true
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
name: 'State',
|
|
169
|
-
value: issue.state,
|
|
170
|
-
inline: true
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
name: 'Labels',
|
|
174
|
-
value: labels,
|
|
175
|
-
inline: false
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: 'Description',
|
|
179
|
-
value: body,
|
|
180
|
-
inline: false
|
|
181
|
-
}
|
|
182
|
-
],
|
|
183
|
-
author: {
|
|
184
|
-
name: issue.user.login,
|
|
185
|
-
icon_url: issue.user.avatar_url
|
|
186
|
-
},
|
|
187
|
-
footer: {
|
|
188
|
-
text: repo
|
|
189
|
-
},
|
|
190
|
-
timestamp: new Date().toISOString()
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
console.log(JSON.stringify({ embeds: [embed] }));
|
|
194
|
-
JS_EOF
|
|
195
|
-
|
|
196
|
-
# Run the Node.js script
|
|
197
|
-
PAYLOAD=$(node /tmp/discord_payload.js)
|
|
198
|
-
|
|
199
|
-
# Send to Discord with error handling
|
|
200
|
-
HTTP_CODE=$(curl -s -o /tmp/discord_response.txt -w "%{http_code}" \
|
|
201
|
-
-X POST "$DISCORD_WEBHOOK_URL" \
|
|
202
|
-
-H "Content-Type: application/json" \
|
|
203
|
-
-d "$PAYLOAD")
|
|
204
|
-
|
|
205
|
-
# Check response
|
|
206
|
-
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
207
|
-
echo "✅ Successfully sent notification to Discord"
|
|
208
|
-
|
|
209
|
-
# Mark issue as notified by adding label (for "opened" events or initial "edited" notifications)
|
|
210
|
-
# This prevents duplicate initial notifications
|
|
211
|
-
if [ "$ACTION" = "opened" ] || [ -z "$HAS_LABEL" ]; then
|
|
212
|
-
# Check if label exists, create if not
|
|
213
|
-
LABEL_EXISTS=$(gh label list --repo "$REPO" --json name --jq ".[] | select(.name == \"$TRACKING_LABEL\") | .name" 2>/dev/null || echo "")
|
|
214
|
-
|
|
215
|
-
if [ -z "$LABEL_EXISTS" ]; then
|
|
216
|
-
echo "Creating tracking label: $TRACKING_LABEL"
|
|
217
|
-
gh label create "$TRACKING_LABEL" \
|
|
218
|
-
--repo "$REPO" \
|
|
219
|
-
--color "0E8A16" \
|
|
220
|
-
--description "Issue has been notified to Discord" \
|
|
221
|
-
2>/dev/null || true
|
|
222
|
-
fi
|
|
223
|
-
|
|
224
|
-
# Add label to issue to mark as notified
|
|
225
|
-
echo "Marking issue #$ISSUE_NUMBER as notified"
|
|
226
|
-
gh issue edit "$ISSUE_NUMBER" \
|
|
227
|
-
--repo "$REPO" \
|
|
228
|
-
--add-label "$TRACKING_LABEL" \
|
|
229
|
-
2>/dev/null || echo "⚠️ Could not add label (may already exist)"
|
|
230
|
-
fi
|
|
231
|
-
else
|
|
232
|
-
echo "❌ Failed to send notification (HTTP $HTTP_CODE)"
|
|
233
|
-
# Log error response without exposing webhook URL
|
|
234
|
-
if [ -f /tmp/discord_response.txt ]; then
|
|
235
|
-
echo "Response: $(cat /tmp/discord_response.txt)"
|
|
236
|
-
fi
|
|
237
|
-
exit 1
|
|
238
|
-
fi
|
|
239
|
-
|
|
240
|
-
# Clean up
|
|
241
|
-
rm -f /tmp/discord_response.txt /tmp/discord_payload.js
|
|
242
|
-
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
name: Discord Release Notifications
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published, edited, prereleased, released]
|
|
6
|
-
|
|
7
|
-
# Security: Limit permissions to only what's needed
|
|
8
|
-
permissions:
|
|
9
|
-
contents: read
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
notify:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- name: Send Release Notification to Discord
|
|
16
|
-
env:
|
|
17
|
-
DISCORD_VERSION_WEBHOOK_URL: ${{ secrets.DISCORD_VERSION_WEBHOOK_URL }}
|
|
18
|
-
run: |
|
|
19
|
-
set -e # Exit on error
|
|
20
|
-
set +x # Don't echo commands (prevents secret exposure in logs)
|
|
21
|
-
|
|
22
|
-
# Mask the webhook URL in logs to prevent accidental exposure
|
|
23
|
-
echo "::add-mask::$DISCORD_VERSION_WEBHOOK_URL"
|
|
24
|
-
|
|
25
|
-
# Validate secret is set
|
|
26
|
-
if [ -z "$DISCORD_VERSION_WEBHOOK_URL" ]; then
|
|
27
|
-
echo "❌ DISCORD_VERSION_WEBHOOK_URL secret is not set"
|
|
28
|
-
exit 1
|
|
29
|
-
fi
|
|
30
|
-
|
|
31
|
-
# Validate webhook URL format for security
|
|
32
|
-
if [[ ! "$DISCORD_VERSION_WEBHOOK_URL" =~ ^https://discord\.com/api/webhooks/[0-9]+/[A-Za-z0-9_-]+$ ]]; then
|
|
33
|
-
echo "❌ Invalid Discord webhook URL format"
|
|
34
|
-
exit 1
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
# Get release information
|
|
38
|
-
RELEASE_TAG="${{ github.event.release.tag_name }}"
|
|
39
|
-
RELEASE_NAME="${{ github.event.release.name }}"
|
|
40
|
-
RELEASE_BODY="${{ github.event.release.body }}"
|
|
41
|
-
RELEASE_URL="${{ github.event.release.html_url }}"
|
|
42
|
-
RELEASE_AUTHOR="${{ github.event.release.author.login }}"
|
|
43
|
-
RELEASE_PRERELEASE="${{ github.event.release.prerelease }}"
|
|
44
|
-
RELEASE_ACTION="${{ github.event.action }}"
|
|
45
|
-
|
|
46
|
-
REPO="${{ github.repository }}"
|
|
47
|
-
|
|
48
|
-
# Determine release type and formatting
|
|
49
|
-
if [ "$RELEASE_PRERELEASE" = "true" ]; then
|
|
50
|
-
COLOR="15105570" # Orange
|
|
51
|
-
EMOJI="🧪"
|
|
52
|
-
TITLE="Pre-Release Published"
|
|
53
|
-
else
|
|
54
|
-
# Parse version to determine type
|
|
55
|
-
VERSION_TYPE=$(node <<VERSION_SCRIPT
|
|
56
|
-
const tag = '$RELEASE_TAG';
|
|
57
|
-
// Remove 'v' prefix if present
|
|
58
|
-
const version = tag.replace(/^v/i, '');
|
|
59
|
-
const parts = version.split('.').map(function(p) { return parseInt(p) || 0; });
|
|
60
|
-
|
|
61
|
-
if (parts[0] > 0 && parts[1] === 0 && parts[2] === 0) {
|
|
62
|
-
console.log('major');
|
|
63
|
-
} else if (parts[1] > 0 && parts[2] === 0) {
|
|
64
|
-
console.log('minor');
|
|
65
|
-
} else {
|
|
66
|
-
console.log('patch');
|
|
67
|
-
}
|
|
68
|
-
VERSION_SCRIPT
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
case "$VERSION_TYPE" in
|
|
72
|
-
major)
|
|
73
|
-
COLOR="15158332" # Red
|
|
74
|
-
EMOJI="🚀"
|
|
75
|
-
TITLE="Major Release"
|
|
76
|
-
;;
|
|
77
|
-
minor)
|
|
78
|
-
COLOR="3066993" # Green
|
|
79
|
-
EMOJI="✨"
|
|
80
|
-
TITLE="Minor Release"
|
|
81
|
-
;;
|
|
82
|
-
patch)
|
|
83
|
-
COLOR="3447003" # Blue
|
|
84
|
-
EMOJI="🔧"
|
|
85
|
-
TITLE="Patch Release"
|
|
86
|
-
;;
|
|
87
|
-
*)
|
|
88
|
-
COLOR="3447003" # Blue
|
|
89
|
-
EMOJI="📦"
|
|
90
|
-
TITLE="Release Published"
|
|
91
|
-
;;
|
|
92
|
-
esac
|
|
93
|
-
fi
|
|
94
|
-
|
|
95
|
-
# Handle different release actions
|
|
96
|
-
case "$RELEASE_ACTION" in
|
|
97
|
-
published)
|
|
98
|
-
# Already set above
|
|
99
|
-
;;
|
|
100
|
-
edited)
|
|
101
|
-
COLOR="15844367" # Gold
|
|
102
|
-
EMOJI="✏️"
|
|
103
|
-
TITLE="Release Edited"
|
|
104
|
-
;;
|
|
105
|
-
prereleased)
|
|
106
|
-
COLOR="15105570" # Orange
|
|
107
|
-
EMOJI="🧪"
|
|
108
|
-
TITLE="Pre-Release Published"
|
|
109
|
-
;;
|
|
110
|
-
released)
|
|
111
|
-
# Use version-based formatting
|
|
112
|
-
;;
|
|
113
|
-
esac
|
|
114
|
-
|
|
115
|
-
# Export variables for Node.js script
|
|
116
|
-
export EMOJI TITLE COLOR
|
|
117
|
-
|
|
118
|
-
# Use Node.js to properly build JSON payload with escaping
|
|
119
|
-
cat > /tmp/discord_version_payload.js <<JS_EOF
|
|
120
|
-
const repo = "$REPO";
|
|
121
|
-
const emoji = process.env.EMOJI || '📦';
|
|
122
|
-
const title = process.env.TITLE || 'Release Published';
|
|
123
|
-
const color = parseInt(process.env.COLOR || '3447003', 10);
|
|
124
|
-
const releaseTag = '$RELEASE_TAG';
|
|
125
|
-
const releaseName = '$RELEASE_NAME';
|
|
126
|
-
const releaseBody = '$RELEASE_BODY';
|
|
127
|
-
const releaseUrl = '$RELEASE_URL';
|
|
128
|
-
const releaseAuthor = '$RELEASE_AUTHOR';
|
|
129
|
-
const isPrerelease = '$RELEASE_PRERELEASE' === 'true';
|
|
130
|
-
|
|
131
|
-
// Truncate release body if too long
|
|
132
|
-
let body = releaseBody || '*No release notes*';
|
|
133
|
-
if (body.length > 1000) {
|
|
134
|
-
body = body.substring(0, 1000) + '...';
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Build embed
|
|
138
|
-
const embed = {
|
|
139
|
-
title: emoji + ' ' + title,
|
|
140
|
-
description: '**' + (releaseName || releaseTag) + '**' + (isPrerelease ? ' (Pre-release)' : ''),
|
|
141
|
-
url: releaseUrl,
|
|
142
|
-
color: color,
|
|
143
|
-
fields: [
|
|
144
|
-
{
|
|
145
|
-
name: 'Tag',
|
|
146
|
-
value: String.fromCharCode(96) + releaseTag + String.fromCharCode(96),
|
|
147
|
-
inline: true
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
name: 'Type',
|
|
151
|
-
value: isPrerelease ? 'Pre-release' : 'Release',
|
|
152
|
-
inline: true
|
|
153
|
-
}
|
|
154
|
-
],
|
|
155
|
-
footer: {
|
|
156
|
-
text: repo + ' • ' + releaseAuthor
|
|
157
|
-
},
|
|
158
|
-
timestamp: new Date().toISOString()
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// Add release notes if available
|
|
162
|
-
if (body && body !== '*No release notes*') {
|
|
163
|
-
embed.fields.push({
|
|
164
|
-
name: 'Release Notes',
|
|
165
|
-
value: body,
|
|
166
|
-
inline: false
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
console.log(JSON.stringify({ embeds: [embed] }));
|
|
171
|
-
JS_EOF
|
|
172
|
-
|
|
173
|
-
# Run the Node.js script
|
|
174
|
-
PAYLOAD=$(node /tmp/discord_version_payload.js)
|
|
175
|
-
|
|
176
|
-
# Send to Discord with error handling
|
|
177
|
-
HTTP_CODE=$(curl -s -o /tmp/discord_response.txt -w "%{http_code}" \
|
|
178
|
-
-X POST "$DISCORD_VERSION_WEBHOOK_URL" \
|
|
179
|
-
-H "Content-Type: application/json" \
|
|
180
|
-
-d "$PAYLOAD")
|
|
181
|
-
|
|
182
|
-
# Check response
|
|
183
|
-
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
184
|
-
echo "✅ Successfully sent version update notification to Discord"
|
|
185
|
-
else
|
|
186
|
-
echo "❌ Failed to send notification (HTTP $HTTP_CODE)"
|
|
187
|
-
if [ -f /tmp/discord_response.txt ]; then
|
|
188
|
-
echo "Response: $(cat /tmp/discord_response.txt)"
|
|
189
|
-
fi
|
|
190
|
-
exit 1
|
|
191
|
-
fi
|
|
192
|
-
|
|
193
|
-
# Clean up
|
|
194
|
-
rm -f /tmp/discord_response.txt /tmp/discord_version_payload.js
|
|
195
|
-
|
package/.prettierignore
DELETED
package/.prettierrc
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"singleQuote": true,
|
|
3
|
-
"trailingComma": "es5",
|
|
4
|
-
"tabWidth": 2,
|
|
5
|
-
"semi": true,
|
|
6
|
-
"printWidth": 80,
|
|
7
|
-
"overrides": [
|
|
8
|
-
{
|
|
9
|
-
"files": "*.zen",
|
|
10
|
-
"options": {
|
|
11
|
-
"parser": "html"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"files": "*.ts",
|
|
16
|
-
"options": {
|
|
17
|
-
"parser": "typescript"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|
package/.zen.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Type definitions for .zen files
|
|
2
|
-
// This file tells the TypeScript linter that 'state' is a valid keyword in .zen files
|
|
3
|
-
|
|
4
|
-
declare global {
|
|
5
|
-
// State declarations are valid in .zen script tags
|
|
6
|
-
// The compiler processes these at compile time
|
|
7
|
-
const state: never; // Prevent accidental use in regular TypeScript files
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Note: The 'state' keyword is processed by the Zenith compiler
|
|
11
|
-
// and transformed into runtime code. Linter errors for 'state' in .zen files
|
|
12
|
-
// are expected and can be ignored - the compiler handles them correctly.
|
|
13
|
-
|
|
14
|
-
export {};
|
|
15
|
-
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
type Props = {
|
|
3
|
-
onClick?: (count: number) => void
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
state count = 0
|
|
7
|
-
|
|
8
|
-
function handleClick() {
|
|
9
|
-
// Internal state mutation
|
|
10
|
-
count += 1
|
|
11
|
-
// Call parent callback prop if provided
|
|
12
|
-
if (onClick) {
|
|
13
|
-
onClick(count)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<style>
|
|
19
|
-
.btn {
|
|
20
|
-
padding: 8px 16px;
|
|
21
|
-
background: #007bff;
|
|
22
|
-
color: white;
|
|
23
|
-
border-radius: 4px;
|
|
24
|
-
cursor: pointer;
|
|
25
|
-
border: none;
|
|
26
|
-
margin: 4px;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.btn-clicked {
|
|
30
|
-
background: #0056b3;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.btn-large {
|
|
34
|
-
padding: 12px 24px;
|
|
35
|
-
font-size: 16px;
|
|
36
|
-
}
|
|
37
|
-
</style>
|
|
38
|
-
|
|
39
|
-
<button
|
|
40
|
-
class="btn"
|
|
41
|
-
:class="{ 'btn-clicked': count > 0, 'btn-large': count > 5 }"
|
|
42
|
-
onclick="handleClick"
|
|
43
|
-
>
|
|
44
|
-
Click Me { count }
|
|
45
|
-
</button>
|
|
46
|
-
|
package/app/components/Link.zen
DELETED
package/app/favicon.ico
DELETED
|
Binary file
|