snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
This commit is contained in:
124
internal/scripts/lib/discord.ts
Normal file
124
internal/scripts/lib/discord.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
const MASK_PLACEHOLDER = '\x00MASKED\x00'
|
||||
|
||||
function sanitizeVariables(errorOutput: string, secretValues?: string[]): string {
|
||||
let sanitized = errorOutput
|
||||
|
||||
// Value-based masking: replace any occurrence of known secret values (like GitHub Actions).
|
||||
// Uses an internal placeholder so regex patterns below can't re-match masked output.
|
||||
// Sort longest-first so a longer secret is masked before a shorter substring of it.
|
||||
if (secretValues) {
|
||||
const sorted = secretValues.filter((v) => v.length >= 8).sort((a, b) => b.length - a.length)
|
||||
for (const value of sorted) {
|
||||
sanitized = sanitized.replaceAll(value, MASK_PLACEHOLDER)
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize wrangler --var KEY:VALUE patterns
|
||||
sanitized = sanitized.replace(/(--var\s+)(\w+):[^ \n]+/g, '$1$2:`***`')
|
||||
|
||||
// Sanitize KEY=VALUE patterns where KEY looks like an env var and value is long enough
|
||||
// to be a secret (e.g. flyctl secrets set). Short values like =debug are left alone.
|
||||
sanitized = sanitized.replace(/\b([A-Z][A-Z_0-9]{2,})=([^ \n]{8,})/g, '$1=`***`')
|
||||
|
||||
// Sanitize --token VALUE and --token=VALUE patterns (e.g. vercel --token xxx)
|
||||
sanitized = sanitized.replace(/(--token[\s=])\S+/g, '$1`***`')
|
||||
|
||||
// Sanitize connection strings (postgres://, redis://, etc.)
|
||||
sanitized = sanitized.replace(
|
||||
/\b(postgres|postgresql|mysql|redis|mongodb|amqp):\/\/[^\s"']+/gi,
|
||||
'$1://`***`'
|
||||
)
|
||||
|
||||
// Replace internal placeholder with final mask
|
||||
sanitized = sanitized.replaceAll(MASK_PLACEHOLDER, '`***`')
|
||||
|
||||
return sanitized
|
||||
}
|
||||
|
||||
export class Discord {
|
||||
static AT_TEAM_MENTION = '<@&1414904550917144586>'
|
||||
|
||||
constructor(opts: {
|
||||
webhookUrl: string
|
||||
shouldNotify: boolean
|
||||
totalSteps?: number
|
||||
messagePrefix?: string
|
||||
secretValues?: string[]
|
||||
}) {
|
||||
this.webhookUrl = opts.webhookUrl
|
||||
this.shouldNotify = opts.shouldNotify
|
||||
this.totalSteps = opts.totalSteps ?? 0
|
||||
this.messagePrefix = opts.messagePrefix ?? ''
|
||||
this.secretValues = opts.secretValues
|
||||
}
|
||||
|
||||
webhookUrl: string
|
||||
shouldNotify: boolean
|
||||
totalSteps: number
|
||||
currentStep = 0
|
||||
messagePrefix: string
|
||||
private secretValues?: string[]
|
||||
|
||||
private async send(method: string, url: string, body: unknown): Promise<any> {
|
||||
try {
|
||||
const response = await fetch(`${this.webhookUrl}${url}`, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
if (!response.ok) {
|
||||
console.warn(
|
||||
`Discord webhook request failed: ${method} -> ${response.status} ${response.statusText}`
|
||||
)
|
||||
return null
|
||||
}
|
||||
return response.json()
|
||||
} catch (err) {
|
||||
const errString = err instanceof Error ? (err.stack ?? err.message) : String(err)
|
||||
console.warn(
|
||||
`Discord webhook request failed: ${method}\n${sanitizeVariables(errString, this.secretValues)}`
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async message(content: string, { always = false }: { always?: boolean } = {}) {
|
||||
if (!always && !this.shouldNotify) {
|
||||
return {
|
||||
edit: () => {
|
||||
// noop
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const prefixedContent = this.messagePrefix ? `${this.messagePrefix} ${content}` : content
|
||||
const message = await this.send('POST', '?wait=true', {
|
||||
content: sanitizeVariables(prefixedContent, this.secretValues),
|
||||
})
|
||||
|
||||
return {
|
||||
edit: async (newContent: string) => {
|
||||
if (!message?.id) return
|
||||
const prefixedNewContent = this.messagePrefix
|
||||
? `${this.messagePrefix} ${newContent}`
|
||||
: newContent
|
||||
await this.send('PATCH', `/messages/${message.id}`, {
|
||||
content: sanitizeVariables(prefixedNewContent, this.secretValues),
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async step<T>(content: string, cb: () => Promise<T>): Promise<T> {
|
||||
this.currentStep++
|
||||
const message = await this.message(`[${this.currentStep}/${this.totalSteps}] ${content}...`)
|
||||
try {
|
||||
const result = await cb()
|
||||
await message.edit(`${content} ✅`)
|
||||
return result
|
||||
} catch (err) {
|
||||
await message.edit(`${content} ❌`)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user