@artian-techs/adonis-orbit 0.1.0

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.
Files changed (45) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +275 -0
  3. package/build/configure.d.ts +8 -0
  4. package/build/configure.js +38 -0
  5. package/build/index.d.ts +10 -0
  6. package/build/index.js +9 -0
  7. package/build/providers/orbit_provider.d.ts +13 -0
  8. package/build/providers/orbit_provider.js +35 -0
  9. package/build/src/auth/basic_auth.d.ts +12 -0
  10. package/build/src/auth/basic_auth.js +36 -0
  11. package/build/src/controllers/dashboard_controller.d.ts +51 -0
  12. package/build/src/controllers/dashboard_controller.js +341 -0
  13. package/build/src/define_config.d.ts +5 -0
  14. package/build/src/define_config.js +6 -0
  15. package/build/src/jobs/prune_job_runs.d.ts +20 -0
  16. package/build/src/jobs/prune_job_runs.js +27 -0
  17. package/build/src/logo.d.ts +4 -0
  18. package/build/src/logo.js +12 -0
  19. package/build/src/middleware/dashboard_auth.d.ts +10 -0
  20. package/build/src/middleware/dashboard_auth.js +16 -0
  21. package/build/src/models/job_run.d.ts +35 -0
  22. package/build/src/models/job_run.js +71 -0
  23. package/build/src/models/silenced_job.d.ts +14 -0
  24. package/build/src/models/silenced_job.js +27 -0
  25. package/build/src/recorder.d.ts +14 -0
  26. package/build/src/recorder.js +102 -0
  27. package/build/src/retry.d.ts +9 -0
  28. package/build/src/retry.js +18 -0
  29. package/build/src/routes.d.ts +8 -0
  30. package/build/src/routes.js +20 -0
  31. package/build/src/sinks/database_sink.d.ts +16 -0
  32. package/build/src/sinks/database_sink.js +88 -0
  33. package/build/src/types.d.ts +92 -0
  34. package/build/src/types.js +1 -0
  35. package/build/stubs/config/orbit.stub +31 -0
  36. package/build/stubs/main.d.ts +1 -0
  37. package/build/stubs/main.js +1 -0
  38. package/build/stubs/migrations/create_job_runs_table.stub +62 -0
  39. package/build/stubs/migrations/create_silenced_jobs_table.stub +29 -0
  40. package/build/templates/components/layout.edge +174 -0
  41. package/build/templates/index.edge +111 -0
  42. package/build/templates/metrics.edge +59 -0
  43. package/build/templates/orbit.svg +35 -0
  44. package/build/templates/silenced.edge +35 -0
  45. package/package.json +130 -0
@@ -0,0 +1,111 @@
1
+ @component('orbit::components/layout', { title, active, menu, path, logo, favicon, theme })
2
+ @if(showStats)
3
+ <div class="cards">
4
+ <div class="card">
5
+ <div class="value">{{ stats.perMinute }}</div>
6
+ <div class="label">Jobs per minute</div>
7
+ </div>
8
+ <div class="card">
9
+ <div class="value">{{ stats.pastHour }}</div>
10
+ <div class="label">Jobs past hour</div>
11
+ </div>
12
+ <div class="card">
13
+ <div class="value">{{ stats.failedPastWeek }}</div>
14
+ <div class="label">Failed jobs past 7 days</div>
15
+ </div>
16
+ <div class="card">
17
+ <div class="value">{{ stats.running }}</div>
18
+ <div class="label">Jobs running now</div>
19
+ </div>
20
+ </div>
21
+
22
+ <h2>Recent jobs</h2>
23
+ @end
24
+
25
+ <div class="panel">
26
+ <table>
27
+ <thead>
28
+ <tr>
29
+ <th>Job</th>
30
+ <th>Status</th>
31
+ <th>Attempts</th>
32
+ <th>Duration</th>
33
+ <th>Dates</th>
34
+ <th>Details</th>
35
+ <th></th>
36
+ </tr>
37
+ </thead>
38
+ <tbody>
39
+ @each(row in rows)
40
+ <tr>
41
+ <td>
42
+ <b>{{ row.name }}</b>
43
+ <div class="muted">{{ row.queue }}</div>
44
+ <div class="muted">{{ row.jobId }}</div>
45
+ </td>
46
+ <td><span class="status {{ row.status }}">{{ row.statusLabel }}</span></td>
47
+ <td>{{ row.attempts }}</td>
48
+ <td>{{ row.duration ? row.duration + ' ms' : '—' }}</td>
49
+ <td class="muted">
50
+ @if(row.dispatchedAt)
51
+ <div>queued {{ row.dispatchedAt }}</div>
52
+ @end
53
+ @if(row.finishedAt)
54
+ <div>ended {{ row.finishedAt }}</div>
55
+ @end
56
+ @if(row.retriedAt)
57
+ <div>asked again {{ row.retriedAt }}</div>
58
+ @end
59
+ </td>
60
+ <td>
61
+ <details>
62
+ <summary>payload</summary>
63
+ <pre>{{ row.payload }}</pre>
64
+ </details>
65
+ @if(row.error)
66
+ <details>
67
+ <summary>error</summary>
68
+ <pre>{{ row.error }}</pre>
69
+ </details>
70
+ @end
71
+ </td>
72
+ <td>
73
+ <div class="actions">
74
+ @if(row.canRetry)
75
+ <form method="post" action="{{ path }}/runs/{{ row.id }}/retry">
76
+ @if(csrfToken)
77
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
78
+ @end
79
+ <button type="submit">Retry</button>
80
+ </form>
81
+ @elseif(row.retriedJobId)
82
+ <a class="muted" href="{{ path }}?job={{ row.retriedJobId }}">
83
+ asked again{{ row.retriedStatus ? ' — ' + row.retriedStatus : '' }}
84
+ </a>
85
+ @end
86
+ <form method="post" action="{{ path }}/jobs/{{ row.name }}/silence">
87
+ @if(csrfToken)
88
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
89
+ @end
90
+ <button type="submit">Silence</button>
91
+ </form>
92
+ </div>
93
+ </td>
94
+ </tr>
95
+ @else
96
+ <tr><td colspan="7" class="empty">No job yet.</td></tr>
97
+ @end
98
+ </tbody>
99
+ </table>
100
+ </div>
101
+
102
+ <div class="pager">
103
+ @if(page > 1)
104
+ <a href="{{ path }}?page={{ page - 1 }}&status={{ status }}">← Previous</a>
105
+ @end
106
+ <span class="muted">Page {{ page }} of {{ lastPage }} — {{ total }} job(s)</span>
107
+ @if(page < lastPage)
108
+ <a href="{{ path }}?page={{ page + 1 }}&status={{ status }}">Next →</a>
109
+ @end
110
+ </div>
111
+ @end
@@ -0,0 +1,59 @@
1
+ @component('orbit::components/layout', { title, active, menu, path, logo, favicon, theme })
2
+ <p class="muted">What each class and each queue cost over the last {{ hours }} hours.</p>
3
+
4
+ <h2>By job</h2>
5
+ <div class="panel">
6
+ <table>
7
+ <thead>
8
+ <tr>
9
+ <th>Job</th>
10
+ <th>Ended</th>
11
+ <th>Failed</th>
12
+ <th>Average</th>
13
+ <th>Longest</th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ @each(row in byJob)
18
+ <tr>
19
+ <td><b>{{ row.label }}</b></td>
20
+ <td>{{ row.total }}</td>
21
+ <td>{{ row.failed }}</td>
22
+ <td>{{ row.average === null ? '—' : row.average + ' ms' }}</td>
23
+ <td>{{ row.longest === null ? '—' : row.longest + ' ms' }}</td>
24
+ </tr>
25
+ @else
26
+ <tr><td colspan="5" class="empty">No job ended in this window.</td></tr>
27
+ @end
28
+ </tbody>
29
+ </table>
30
+ </div>
31
+
32
+ <h2>By queue</h2>
33
+ <div class="panel">
34
+ <table>
35
+ <thead>
36
+ <tr>
37
+ <th>Queue</th>
38
+ <th>Ended</th>
39
+ <th>Failed</th>
40
+ <th>Average</th>
41
+ <th>Longest</th>
42
+ </tr>
43
+ </thead>
44
+ <tbody>
45
+ @each(row in byQueue)
46
+ <tr>
47
+ <td><b>{{ row.label }}</b></td>
48
+ <td>{{ row.total }}</td>
49
+ <td>{{ row.failed }}</td>
50
+ <td>{{ row.average === null ? '—' : row.average + ' ms' }}</td>
51
+ <td>{{ row.longest === null ? '—' : row.longest + ' ms' }}</td>
52
+ </tr>
53
+ @else
54
+ <tr><td colspan="5" class="empty">No job ended in this window.</td></tr>
55
+ @end
56
+ </tbody>
57
+ </table>
58
+ </div>
59
+ @end
@@ -0,0 +1,35 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="19.58 29.17 100.83 88.83">
2
+ <defs>
3
+ <linearGradient id="orbit-primary" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#6366F1"/>
5
+ <stop offset="50%" stop-color="#8B5CF6"/>
6
+ <stop offset="100%" stop-color="#D946EF"/>
7
+ </linearGradient>
8
+
9
+ <linearGradient id="orbit-accent" x1="0%" y1="0%" x2="100%" y2="0%">
10
+ <stop offset="0%" stop-color="#06B6D4"/>
11
+ <stop offset="100%" stop-color="#3B82F6"/>
12
+ </linearGradient>
13
+
14
+ <filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
15
+ <feDropShadow dx="0" dy="4" stdDeviation="6" flood-color="#6366F1" flood-opacity="0.25"/>
16
+ </filter>
17
+ </defs>
18
+
19
+ <g transform="translate(10, 10)">
20
+ <!-- Anneau secondaire (arrière-plan) -->
21
+ <ellipse cx="60" cy="60" rx="50" ry="20" fill="none" stroke="url(#orbit-accent)" stroke-width="3.5" transform="rotate(-30 60 60)" opacity="0.7"/>
22
+
23
+ <!-- Anneau principal (complet et continu) -->
24
+ <ellipse cx="60" cy="60" rx="52" ry="22" fill="none" stroke="url(#orbit-primary)" stroke-width="5" transform="rotate(35 60 60)" filter="url(#soft-shadow)"/>
25
+
26
+ <!-- Noyau central -->
27
+ <circle cx="60" cy="60" r="14" fill="url(#orbit-primary)"/>
28
+ <circle cx="60" cy="60" r="6" fill="#FFFFFF" opacity="0.9"/>
29
+
30
+ <!-- Jobs / Workers en orbite -->
31
+ <circle cx="102" cy="38" r="6" fill="#06B6D4" filter="url(#soft-shadow)"/>
32
+ <circle cx="18" cy="82" r="5" fill="#D946EF"/>
33
+ <circle cx="78" cy="104" r="4" fill="#3B82F6"/>
34
+ </g>
35
+ </svg>
@@ -0,0 +1,35 @@
1
+ @component('orbit::components/layout', { title, active, menu, path, logo, favicon, theme })
2
+ <p class="muted" style="max-width: 640px">
3
+ These job classes are left out of the lists. Their work goes on and their
4
+ trace is written. Take a name away, and everything it did comes back,
5
+ including what it did while it was silent.
6
+ </p>
7
+
8
+ <div class="panel">
9
+ <table>
10
+ <thead>
11
+ <tr>
12
+ <th>Job</th>
13
+ <th></th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ @each(name in names)
18
+ <tr>
19
+ <td><b>{{ name }}</b></td>
20
+ <td>
21
+ <form method="post" action="{{ path }}/jobs/{{ name }}/silence">
22
+ @if(csrfToken)
23
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
24
+ @end
25
+ <button type="submit">Show again</button>
26
+ </form>
27
+ </td>
28
+ </tr>
29
+ @else
30
+ <tr><td colspan="2" class="empty">No job is silenced.</td></tr>
31
+ @end
32
+ </tbody>
33
+ </table>
34
+ </div>
35
+ @end
package/package.json ADDED
@@ -0,0 +1,130 @@
1
+ {
2
+ "name": "@artian-techs/adonis-orbit",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "See what the queue of AdonisJS does, keep it, and ask a job again.",
6
+ "main": "build/index.js",
7
+ "exports": {
8
+ ".": "./build/index.js",
9
+ "./types": "./build/src/types.js",
10
+ "./orbit_provider": "./build/providers/orbit_provider.js",
11
+ "./stubs/*": "./build/stubs/*"
12
+ },
13
+ "files": [
14
+ "build/index.js",
15
+ "build/index.d.ts",
16
+ "build/configure.js",
17
+ "build/configure.d.ts",
18
+ "build/src",
19
+ "build/providers",
20
+ "build/stubs",
21
+ "build/templates",
22
+ "LICENSE.md",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "pnpm run compile",
27
+ "clean": "del-cli build",
28
+ "compile": "pnpm run clean && tsc",
29
+ "copy:templates": "cpy \"stubs/**/*.stub\" build/stubs && cpy \"templates/**/*.{edge,svg}\" build/templates",
30
+ "postcompile": "pnpm run copy:templates",
31
+ "test": "node --enable-source-maps --import=@poppinss/ts-exec bin/test.ts",
32
+ "preview": "node --enable-source-maps --import=@poppinss/ts-exec bin/preview.ts",
33
+ "typecheck": "tsc --noEmit",
34
+ "lint": "eslint .",
35
+ "format": "prettier --write .",
36
+ "checks": "pnpm lint && pnpm typecheck",
37
+ "prepublishOnly": "pnpm run build",
38
+ "release": "release-it"
39
+ },
40
+ "prettier": "@adonisjs/prettier-config",
41
+ "keywords": [
42
+ "adonisjs",
43
+ "queue",
44
+ "jobs",
45
+ "dashboard"
46
+ ],
47
+ "license": "MIT",
48
+ "author": {
49
+ "name": "Oussama Benhamed",
50
+ "email": "b.oussama@corposmart.dz"
51
+ },
52
+ "homepage": "https://github.com/artian-techs/adonis-orbit#readme",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/artian-techs/adonis-orbit.git"
56
+ },
57
+ "bugs": {
58
+ "url": "https://github.com/artian-techs/adonis-orbit/issues"
59
+ },
60
+ "packageManager": "pnpm@10.24.0",
61
+ "engines": {
62
+ "node": ">=24.0.0"
63
+ },
64
+ "peerDependencies": {
65
+ "@adonisjs/assembler": "^7.0.0 || ^8.0.0",
66
+ "@adonisjs/core": "^6.18.0 || ^7.0.0",
67
+ "@adonisjs/lucid": "^21.0.0 || ^22.0.0",
68
+ "@adonisjs/queue": "^0.6.0",
69
+ "edge.js": "^6.0.0",
70
+ "luxon": "^3.0.0"
71
+ },
72
+ "devDependencies": {
73
+ "@adonisjs/assembler": "^8.5.0",
74
+ "@adonisjs/core": "^7.4.0",
75
+ "@adonisjs/eslint-config": "^3.1.0",
76
+ "@adonisjs/lucid": "^22.4.2",
77
+ "@adonisjs/prettier-config": "^1.5.0",
78
+ "@adonisjs/queue": "^0.6.2",
79
+ "@adonisjs/tsconfig": "^2.0.0",
80
+ "@japa/assert": "^4.2.0",
81
+ "@japa/runner": "^5.3.0",
82
+ "@poppinss/ts-exec": "^1.4.4",
83
+ "@release-it/conventional-changelog": "^12.0.0",
84
+ "@types/luxon": "^3.7.4",
85
+ "@types/node": "^24.13.3",
86
+ "@types/pg": "^8.23.1",
87
+ "cpy-cli": "^5.0.0",
88
+ "del-cli": "^6.0.0",
89
+ "edge.js": "^6.0.2",
90
+ "eslint": "^10.8.1",
91
+ "luxon": "^3.5.0",
92
+ "pg": "^8.23.0",
93
+ "prettier": "^3.9.6",
94
+ "release-it": "^21.0.2",
95
+ "typescript": "^6.0.3"
96
+ },
97
+ "peerDependenciesMeta": {
98
+ "@adonisjs/assembler": {
99
+ "optional": true
100
+ }
101
+ },
102
+ "publishConfig": {
103
+ "access": "public",
104
+ "tag": "latest"
105
+ },
106
+ "release-it": {
107
+ "git": {
108
+ "requireCleanWorkingDir": true,
109
+ "requireUpstream": true,
110
+ "commitMessage": "chore(release): ${version}",
111
+ "tagAnnotation": "v${version}",
112
+ "push": true,
113
+ "tagName": "v${version}"
114
+ },
115
+ "github": {
116
+ "release": true
117
+ },
118
+ "npm": {
119
+ "publish": true,
120
+ "skipChecks": true
121
+ },
122
+ "plugins": {
123
+ "@release-it/conventional-changelog": {
124
+ "preset": {
125
+ "name": "angular"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }