@stacksjs/defaults 0.75.41 → 0.75.43
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/ai/skills/stacks-actions/SKILL.md +1 -1
- package/ai/skills/stacks-auto-imports/SKILL.md +1 -1
- package/ai/skills/stacks-chat/SKILL.md +51 -1
- package/ai/skills/stacks-cloud/SKILL.md +36 -0
- package/ai/skills/stacks-dashboard/SKILL.md +16 -2
- package/ai/skills/stacks-database/SKILL.md +24 -3
- package/ai/skills/stacks-deploy/SKILL.md +7 -1
- package/ai/skills/stacks-desktop/SKILL.md +10 -0
- package/ai/skills/stacks-development/SKILL.md +1 -1
- package/ai/skills/stacks-migrations/SKILL.md +2 -2
- package/ai/skills/stacks-models/SKILL.md +38 -2
- package/ai/skills/stacks-orm/SKILL.md +2 -2
- package/ai/skills/stacks-security/SKILL.md +28 -1
- package/app/Actions/Auth/DataExportAction.test.ts +84 -0
- package/app/Actions/Auth/DataExportAction.ts +40 -0
- package/app/Actions/Dashboard/Content/FileReprocessAction.ts +1 -1
- package/app/Actions/Dashboard/Content/file-manager.ts +120 -8
- package/app/Actions/Dashboard/Content/file-metadata.ts +108 -12
- package/app/Actions/Dashboard/Content/file-pipeline.test.ts +13 -9
- package/app/Actions/Dashboard/Content/file-preview.test.ts +487 -0
- package/app/Actions/Dashboard/Content/file-preview.ts +548 -0
- package/app/Jobs/GenerateStoragePreviewJob.ts +47 -0
- package/app/Jobs/OptimizeStorageImageJob.ts +7 -3
- package/app/Jobs/PruneRetainedDataJob.ts +46 -0
- package/app/Models/Activity.ts +2 -0
- package/app/Models/CampaignSend.ts +2 -0
- package/app/Models/Card.ts +1 -0
- package/app/Models/CardComment.ts +1 -0
- package/app/Models/Comment.ts +5 -0
- package/app/Models/CommunicationSuppression.ts +2 -1
- package/app/Models/ConsentEvent.ts +4 -3
- package/app/Models/Content/Author.ts +5 -0
- package/app/Models/EmailListSubscriber.ts +1 -0
- package/app/Models/EmailSuppression.ts +2 -0
- package/app/Models/Forms/FormSubmission.ts +5 -0
- package/app/Models/GdprRequest.ts +77 -0
- package/app/Models/MagicLinkToken.ts +2 -0
- package/app/Models/Notification.ts +2 -0
- package/app/Models/NotificationDelivery.ts +4 -0
- package/app/Models/PaymentMethod.ts +5 -0
- package/app/Models/PaymentTransaction.ts +1 -0
- package/app/Models/PersonalAccessToken.ts +3 -0
- package/app/Models/Referral.ts +4 -1
- package/app/Models/ReferralCode.ts +4 -1
- package/app/Models/Request.ts +3 -0
- package/app/Models/SmsOptOut.ts +2 -0
- package/app/Models/SocialAccount.ts +3 -0
- package/app/Models/SocialPost.ts +2 -0
- package/app/Models/StorageItemTask.ts +14 -8
- package/app/Models/Subscriber.ts +2 -0
- package/app/Models/SubscriberEmail.ts +2 -0
- package/app/Models/Subscription.ts +1 -0
- package/app/Models/TeamInvitation.ts +2 -0
- package/app/Models/TeamMember.ts +1 -0
- package/app/Models/User.ts +5 -0
- package/app/Models/commerce/Bid.ts +3 -0
- package/app/Models/commerce/Cart.ts +2 -0
- package/app/Models/commerce/Courier.ts +7 -0
- package/app/Models/commerce/CourierPing.ts +3 -0
- package/app/Models/commerce/Customer.ts +5 -0
- package/app/Models/commerce/DeliveryStop.ts +7 -0
- package/app/Models/commerce/GiftCard.ts +4 -0
- package/app/Models/commerce/Order.ts +5 -0
- package/app/Models/commerce/OrderItem.ts +2 -0
- package/app/Models/commerce/Payment.ts +5 -0
- package/app/Models/commerce/Pledge.ts +3 -0
- package/app/Models/commerce/Transaction.ts +2 -0
- package/app/Models/commerce/WaitlistProduct.ts +5 -0
- package/app/Models/commerce/WaitlistRestaurant.ts +4 -0
- package/ide/vscode/.vscode/extensions.json +1 -1
- package/ide/vscode/.vscode/settings.json +8 -149
- package/ide/vscode/README.md +48 -23
- package/ide/vscode/build.ts +43 -0
- package/ide/vscode/package.json +305 -56
- package/ide/vscode/scripts/stx-contributes.ts +66 -0
- package/ide/vscode/src/env-file.ts +103 -0
- package/ide/vscode/src/env.ts +241 -0
- package/ide/vscode/src/extension.ts +120 -26
- package/ide/vscode/src/pickier-protocol.ts +51 -0
- package/ide/vscode/src/pickier-worker.ts +92 -0
- package/ide/vscode/src/pickier.ts +433 -0
- package/ide/vscode/src/project.ts +14 -4
- package/ide/vscode/src/stacks.ts +18 -11
- package/ide/vscode/tests/build.test.ts +58 -0
- package/ide/vscode/tests/env.test.ts +166 -0
- package/ide/vscode/tests/extension.test.ts +8 -0
- package/ide/vscode/tests/fake-vscode.ts +228 -0
- package/ide/vscode/tests/manifest.test.ts +88 -0
- package/ide/vscode/tests/pickier.test.ts +202 -0
- package/ide/vscode/tsconfig.json +2 -2
- package/package.json +2 -2
- package/resources/components/Dashboard/Content/FileManagerDashboard.stx +2 -0
- package/resources/components/Dashboard/FileViewer/MediaCard.stx +14 -3
- package/routes/auth.ts +4 -0
- package/vcs/github/workflows/buddy-bot.yml +2 -2
- package/vcs/github/workflows/ci.yml +3 -3
- package/vcs/github/workflows/release.yml +1 -1
- package/ide/vscode/src/vscode.d.ts +0 -181
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pickier support (src/pickier.ts), driven through a fake `vscode` API and a
|
|
3
|
+
* fake worker process: no editor, no Bun, no pickier.
|
|
4
|
+
*/
|
|
5
|
+
import type { PickierProcess } from '../src/pickier'
|
|
6
|
+
import type { PickierRequest, PickierResult } from '../src/pickier-protocol'
|
|
7
|
+
import { describe, expect, it } from 'bun:test'
|
|
8
|
+
import { chooseBun, createPickierSupport, disableNextLineComment, isLintedFile, isPickierConfigPath } from '../src/pickier'
|
|
9
|
+
import { CodeActionKind, document, fakeVscode, flush } from './fake-vscode'
|
|
10
|
+
|
|
11
|
+
const ROOT = '/work/app'
|
|
12
|
+
|
|
13
|
+
interface Worker {
|
|
14
|
+
answer?: (request: PickierRequest) => PickierResult
|
|
15
|
+
ready?: false
|
|
16
|
+
fixText?: boolean
|
|
17
|
+
exitOnStart?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setup(options: { worker?: Worker, files?: string[], settings?: Record<string, unknown>, documents?: ReturnType<typeof document>[] } = {}) {
|
|
21
|
+
const files = new Set(options.files ?? [`${ROOT}/buddy`])
|
|
22
|
+
const fake = fakeVscode({ folders: [ROOT], settings: options.settings, documents: options.documents })
|
|
23
|
+
const spawned: Array<{ bun: string, script: string, cwd: string, requests: PickierRequest[] }> = []
|
|
24
|
+
|
|
25
|
+
const host = {
|
|
26
|
+
exists: (path: string) => files.has(path),
|
|
27
|
+
spawnBun(bun: string, script: string, cwd: string): PickierProcess {
|
|
28
|
+
const record = { bun, script, cwd, requests: [] as PickierRequest[] }
|
|
29
|
+
spawned.push(record)
|
|
30
|
+
const lineListeners: Array<(line: string) => void> = []
|
|
31
|
+
const exitListeners: Array<() => void> = []
|
|
32
|
+
const emit = (message: unknown) => queueMicrotask(() => lineListeners.forEach(listener => listener(JSON.stringify(message))))
|
|
33
|
+
const worker = options.worker ?? {}
|
|
34
|
+
|
|
35
|
+
queueMicrotask(() => {
|
|
36
|
+
if (worker.exitOnStart)
|
|
37
|
+
return exitListeners.forEach(listener => listener())
|
|
38
|
+
if (worker.ready === false)
|
|
39
|
+
return emit({ ready: false, error: 'Cannot find package \'pickier\'', missing: true })
|
|
40
|
+
emit({ ready: true, version: '0.1.66', fixText: worker.fixText ?? true })
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
write(line) {
|
|
45
|
+
const request = JSON.parse(line) as PickierRequest
|
|
46
|
+
record.requests.push(request)
|
|
47
|
+
const result = worker.answer?.(request) ?? (request.op === 'lint' ? { op: 'lint', issues: [] } : { op: request.op, text: null })
|
|
48
|
+
emit({ id: request.id, ok: true, result })
|
|
49
|
+
},
|
|
50
|
+
onLine: listener => lineListeners.push(listener),
|
|
51
|
+
onExit: listener => exitListeners.push(listener),
|
|
52
|
+
kill: () => {},
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const support = createPickierSupport(fake.api as any, host, { workerPath: '/ext/dist/pickier-worker.js', lintDelayMs: 1 })
|
|
58
|
+
support.activate(fake.context)
|
|
59
|
+
return { ...fake, spawned, support }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('helpers', () => {
|
|
63
|
+
it('runs pickier on the configured Bun, else the project\'s pinned Bun, else bun on the PATH', () => {
|
|
64
|
+
expect(chooseBun(' /opt/bun ', ROOT, () => true)).toBe('/opt/bun')
|
|
65
|
+
expect(chooseBun('', ROOT, path => path === `${ROOT}/pantry/.bin/bun`)).toBe(`${ROOT}/pantry/.bin/bun`)
|
|
66
|
+
expect(chooseBun('', ROOT, () => false)).toBe('bun')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('lints exactly the files `buddy lint` does', () => {
|
|
70
|
+
expect(isLintedFile(ROOT, `${ROOT}/app/Actions/Hello.ts`)).toBeTrue()
|
|
71
|
+
expect(isLintedFile(ROOT, `${ROOT}/README.md`)).toBeTrue()
|
|
72
|
+
expect(isLintedFile(ROOT, `${ROOT}/node_modules/x/index.ts`)).toBeFalse()
|
|
73
|
+
expect(isLintedFile(ROOT, `${ROOT}/dist/index.js`)).toBeFalse()
|
|
74
|
+
expect(isLintedFile(ROOT, `${ROOT}/resources/views/index.stx`)).toBeFalse()
|
|
75
|
+
expect(isLintedFile(ROOT, '/elsewhere/a.ts')).toBeFalse()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('recognises the files pickier reads its config from', () => {
|
|
79
|
+
expect(isPickierConfigPath(`${ROOT}/config/code-style.ts`)).toBeTrue()
|
|
80
|
+
expect(isPickierConfigPath(`${ROOT}/pickier.config.ts`)).toBeTrue()
|
|
81
|
+
expect(isPickierConfigPath(`${ROOT}/.config/pickier.ts`)).toBeTrue()
|
|
82
|
+
expect(isPickierConfigPath(`${ROOT}/config/app.ts`)).toBeFalse()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('disables a rule for the next line at that line\'s indentation', () => {
|
|
86
|
+
expect(disableNextLineComment(' let x = 1', 'prefer-const', '//')).toBe(' // pickier-disable-next-line prefer-const\n')
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
describe('diagnostics', () => {
|
|
91
|
+
it('reports the project pickier\'s issues on an open file, in editor coordinates', async () => {
|
|
92
|
+
const file = document(`${ROOT}/app/x.ts`, 'import { a } from \'b\'\nlet x = 1\n')
|
|
93
|
+
const { diagnostics, spawned } = setup({
|
|
94
|
+
documents: [file],
|
|
95
|
+
worker: {
|
|
96
|
+
answer: () => ({ op: 'lint', issues: [{ line: 2, column: 5, ruleId: 'prefer-const', message: '\'x\' is never reassigned', severity: 'error', help: 'Use const' }] }),
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
await flush()
|
|
100
|
+
|
|
101
|
+
expect(spawned).toHaveLength(1)
|
|
102
|
+
expect(spawned[0]).toMatchObject({ bun: 'bun', script: '/ext/dist/pickier-worker.js', cwd: ROOT })
|
|
103
|
+
expect(spawned[0]!.requests[0]).toMatchObject({ op: 'lint', file: `${ROOT}/app/x.ts` })
|
|
104
|
+
|
|
105
|
+
const [diagnostic] = diagnostics.get(`file://${ROOT}/app/x.ts`)!
|
|
106
|
+
expect(diagnostic.source).toBe('pickier')
|
|
107
|
+
expect(diagnostic.code).toBe('prefer-const')
|
|
108
|
+
expect(diagnostic.severity).toBe(0)
|
|
109
|
+
expect(diagnostic.range.start).toMatchObject({ line: 1, character: 4 })
|
|
110
|
+
expect(diagnostic.range.end).toMatchObject({ line: 1, character: 5 })
|
|
111
|
+
expect(diagnostic.message).toBe('\'x\' is never reassigned\nUse const')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('leaves folders that are not Stacks projects alone', async () => {
|
|
115
|
+
const { spawned } = setup({ files: [], documents: [document(`${ROOT}/x.ts`, 'let x = 1\n')] })
|
|
116
|
+
await flush()
|
|
117
|
+
expect(spawned).toHaveLength(0)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('lints nothing when turned off', async () => {
|
|
121
|
+
const { spawned } = setup({ settings: { 'pickier.enable': false }, documents: [document(`${ROOT}/x.ts`, 'let x = 1\n')] })
|
|
122
|
+
await flush()
|
|
123
|
+
expect(spawned).toHaveLength(0)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('stops asking a project with no pickier, and says why once', async () => {
|
|
127
|
+
const { spawned, events, output, diagnostics } = setup({ worker: { ready: false }, documents: [document(`${ROOT}/a.ts`, '')] })
|
|
128
|
+
await flush()
|
|
129
|
+
events.opened.fire(document(`${ROOT}/b.ts`, '') as any)
|
|
130
|
+
await flush()
|
|
131
|
+
|
|
132
|
+
expect(spawned).toHaveLength(1)
|
|
133
|
+
expect(diagnostics.size).toBe(0)
|
|
134
|
+
expect(output.filter(line => line.includes('not available'))).toHaveLength(1)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('gives up on a worker that keeps exiting instead of respawning it on every keystroke', async () => {
|
|
138
|
+
const { spawned, events } = setup({ worker: { exitOnStart: true } })
|
|
139
|
+
for (let i = 0; i < 5; i++) {
|
|
140
|
+
events.opened.fire(document(`${ROOT}/x${i}.ts`, '') as any)
|
|
141
|
+
await flush()
|
|
142
|
+
}
|
|
143
|
+
expect(spawned).toHaveLength(3)
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('fixing and formatting', () => {
|
|
148
|
+
const FIXED = 'const x = 1\n'
|
|
149
|
+
|
|
150
|
+
it('offers source.fixAll.pickier, the code action codeActionsOnSave asks for', async () => {
|
|
151
|
+
const file = document(`${ROOT}/x.ts`, 'let x = 1\n')
|
|
152
|
+
const { codeActionProviders, spawned } = setup({ worker: { answer: request => request.op === 'fix' ? { op: 'fix', text: FIXED } : { op: 'lint', issues: [] } } })
|
|
153
|
+
|
|
154
|
+
const only = CodeActionKind.SourceFixAll.append('pickier')
|
|
155
|
+
const [action] = await codeActionProviders[0].provideCodeActions(file, undefined, { only, diagnostics: [] })
|
|
156
|
+
|
|
157
|
+
expect(action.kind.value).toBe('source.fixAll.pickier')
|
|
158
|
+
expect(action.edit.edits[0].text).toBe(FIXED)
|
|
159
|
+
expect(spawned[0]!.requests.at(-1)!.op).toBe('fix')
|
|
160
|
+
|
|
161
|
+
// The generic `source.fixAll` includes it too.
|
|
162
|
+
const generic = await codeActionProviders[0].provideCodeActions(file, undefined, { only: CodeActionKind.SourceFixAll, diagnostics: [] })
|
|
163
|
+
expect(generic).toHaveLength(1)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('offers nothing when there is nothing to fix, or the project\'s pickier cannot fix text', async () => {
|
|
167
|
+
const file = document(`${ROOT}/x.ts`, FIXED)
|
|
168
|
+
const unchanged = setup({ worker: { answer: request => ({ op: request.op as 'fix', text: FIXED }) } })
|
|
169
|
+
expect(await unchanged.codeActionProviders[0].provideCodeActions(file, undefined, { only: CodeActionKind.SourceFixAll, diagnostics: [] })).toEqual([])
|
|
170
|
+
|
|
171
|
+
const old = setup({ worker: { fixText: false } })
|
|
172
|
+
expect(await old.codeActionProviders[0].provideCodeActions(document(`${ROOT}/x.ts`, 'let x = 1\n'), undefined, { only: CodeActionKind.SourceFixAll, diagnostics: [] })).toEqual([])
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('offers quick fixes for its own diagnostics: fix all, and disable the rule for the line', async () => {
|
|
176
|
+
const file = document(`${ROOT}/x.ts`, 'function f() {\n let x = 1\n}\n')
|
|
177
|
+
const { codeActionProviders } = setup({ worker: { answer: request => request.op === 'fix' ? { op: 'fix', text: 'function f() {\n const x = 1\n}\n' } : { op: 'lint', issues: [] } } })
|
|
178
|
+
const diagnostic = { source: 'pickier', code: 'prefer-const', range: { start: { line: 1, character: 6 } } }
|
|
179
|
+
|
|
180
|
+
const actions = await codeActionProviders[0].provideCodeActions(file, undefined, { diagnostics: [diagnostic, { source: 'ts', code: 1 }] })
|
|
181
|
+
|
|
182
|
+
expect(actions.map((action: any) => action.title)).toEqual(['Fix all pickier problems', 'Disable prefer-const for this line'])
|
|
183
|
+
expect(actions[1].edit.edits[0]).toMatchObject({ position: { line: 1, character: 0 }, text: ' // pickier-disable-next-line prefer-const\n' })
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('formats with the project\'s pickier', async () => {
|
|
187
|
+
const file = document(`${ROOT}/x.ts`, 'const a = "x"\n')
|
|
188
|
+
const { formatters } = setup({ worker: { answer: request => request.op === 'format' ? { op: 'format', text: 'const a = \'x\'\n' } : { op: 'lint', issues: [] } } })
|
|
189
|
+
|
|
190
|
+
const [edit] = await formatters[0].provideDocumentFormattingEdits(file)
|
|
191
|
+
expect(edit.newText).toBe('const a = \'x\'\n')
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('applies the fixes to the active file from the command palette', async () => {
|
|
195
|
+
const file = document(`${ROOT}/x.ts`, 'let x = 1\n')
|
|
196
|
+
const fake = setup({ worker: { answer: request => request.op === 'fix' ? { op: 'fix', text: FIXED } : { op: 'lint', issues: [] } } })
|
|
197
|
+
fake.api.window.activeTextEditor = { document: file }
|
|
198
|
+
|
|
199
|
+
await fake.handlers.get('stacks.pickier.fixAll')!()
|
|
200
|
+
expect(fake.applied[0]!.edits[0]!.text).toBe(FIXED)
|
|
201
|
+
})
|
|
202
|
+
})
|
package/ide/vscode/tsconfig.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"lib": ["es2022"],
|
|
8
8
|
"module": "esnext",
|
|
9
9
|
"moduleResolution": "bundler",
|
|
10
|
-
"types": ["bun"],
|
|
10
|
+
"types": ["bun", "vscode"],
|
|
11
11
|
"strict": true,
|
|
12
12
|
"noUncheckedIndexedAccess": true,
|
|
13
13
|
"noEmit": true,
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
"isolatedModules": true,
|
|
16
16
|
"verbatimModuleSyntax": true
|
|
17
17
|
},
|
|
18
|
-
"include": ["src/**/*.ts", "tests/**/*.ts"]
|
|
18
|
+
"include": ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts"]
|
|
19
19
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.43",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@iconify-json/f7": "^1.2.2",
|
|
57
57
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
58
|
-
"@stacksjs/mobile": "^0.75.
|
|
58
|
+
"@stacksjs/mobile": "^0.75.43",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.348",
|
|
60
60
|
"ts-qr-codes": "^0.1.8"
|
|
61
61
|
}
|
|
@@ -7,6 +7,10 @@ interface FileItem {
|
|
|
7
7
|
mime_type?: string
|
|
8
8
|
url?: string
|
|
9
9
|
thumbnail?: string
|
|
10
|
+
/** A generated preview image (stacksjs/stacks#308): a scaled photo, a waveform, a font specimen. */
|
|
11
|
+
preview?: string
|
|
12
|
+
/** The first lines of a text file, shown as text rather than an image. */
|
|
13
|
+
previewText?: string
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
const EMPTY_ITEM: FileItem = {
|
|
@@ -49,8 +53,14 @@ function kindOf(value: FileItem): string {
|
|
|
49
53
|
|
|
50
54
|
const kind = derived(() => kindOf(currentItem()))
|
|
51
55
|
const extension = derived(() => (currentItem().type || '').toUpperCase())
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
// The generated preview wins over the original: it is a small PNG for any kind
|
|
57
|
+
// that could be drawn, where the original may be a 40 MB photo or not an image
|
|
58
|
+
// at all. Only an image falls back to the original, because only an image can
|
|
59
|
+
// be shown by pointing an <img> at it.
|
|
60
|
+
const previewUrl = derived(() => currentItem().preview || (kind() === 'image' ? currentItem().thumbnail || currentItem().url || '' : ''))
|
|
61
|
+
const hasImage = derived(() => Boolean(previewUrl()))
|
|
62
|
+
const hasText = derived(() => !hasImage() && Boolean(currentItem().previewText))
|
|
63
|
+
const imageClass = derived(() => currentItem().preview && kind() !== 'image' ? 'object-contain h-full w-full' : 'object-cover h-full w-full')
|
|
54
64
|
|
|
55
65
|
const backdropByKind: Record<string, string> = {
|
|
56
66
|
image: 'bg-gradient-to-br from-sky-50 to-indigo-100 dark:from-neutral-800 dark:to-neutral-900',
|
|
@@ -79,7 +89,8 @@ const badgeClass = derived(() => kind() === 'video'
|
|
|
79
89
|
|
|
80
90
|
<div class="flex flex-col">
|
|
81
91
|
<div :class="previewClass()">
|
|
82
|
-
<img :if="hasImage()" :src="previewUrl()" :alt="currentItem().name" loading="lazy" class="
|
|
92
|
+
<img :if="hasImage()" :src="previewUrl()" :alt="currentItem().name" loading="lazy" :class="imageClass()" />
|
|
93
|
+
<pre :else-if="hasText()" class="absolute inset-0 overflow-hidden m-0 pb-2 pt-7 px-3 font-mono leading-[1.35] text-[9px] text-left text-stone-600 whitespace-pre dark:text-neutral-300 bg-white/80 dark:bg-neutral-900/60">{{ currentItem().previewText }}</pre>
|
|
83
94
|
<div :else-if="kind() === 'video'" class="flex items-center justify-center h-12 w-12 bg-white/90 rounded-full shadow-md"><span class="ml-0.5 h-5 w-5 text-neutral-900 i-hugeicons-play"></span></div>
|
|
84
95
|
<span :else :class="glyphClass()"></span>
|
|
85
96
|
<span :if="currentItem().type !== 'folder' && extension()" :class="badgeClass()">{{ extension() }}</span>
|
package/routes/auth.ts
CHANGED
|
@@ -104,6 +104,10 @@ route.group({ middleware: 'auth' }, () => {
|
|
|
104
104
|
route.get('/referrals', 'Actions/Auth/ReferralSummaryAction').rateLimit(60, 'minute')
|
|
105
105
|
route.post('/referrals/code', 'Actions/Auth/CreateReferralCodeAction').rateLimit(10, 'minute')
|
|
106
106
|
route.get('/me', 'Actions/Auth/AuthUserAction')
|
|
107
|
+
// The caller's own personal data as a JSON download (GDPR access and
|
|
108
|
+
// portability, stacksjs/stacks#365). Reads every table the user touches,
|
|
109
|
+
// so it is held to a few an hour; each one is recorded in gdpr_requests.
|
|
110
|
+
route.get('/me/data-export', 'Actions/Auth/DataExportAction').rateLimit(3, 'hour')
|
|
107
111
|
route.post('/logout', 'Actions/Auth/LogoutAction')
|
|
108
112
|
// Sign out everywhere: revoke every access/refresh token AND destroy
|
|
109
113
|
// every session for the authenticated user (stacksjs/stacks#1957).
|
|
@@ -83,9 +83,9 @@ jobs:
|
|
|
83
83
|
persist-credentials: true
|
|
84
84
|
|
|
85
85
|
- name: Setup Pantry
|
|
86
|
-
uses: pantry-pm/pantry/packages/action@
|
|
86
|
+
uses: pantry-pm/pantry/packages/action@00f7f8d0f4b166db35d2e1405fdcefd442acd775 # v0.11.68
|
|
87
87
|
with:
|
|
88
|
-
version: '0.11.
|
|
88
|
+
version: '0.11.68'
|
|
89
89
|
install: 'false'
|
|
90
90
|
|
|
91
91
|
- name: Install Dependencies
|
|
@@ -30,7 +30,7 @@ jobs:
|
|
|
30
30
|
uses: actions/checkout@v4
|
|
31
31
|
|
|
32
32
|
- name: Setup Pantry
|
|
33
|
-
uses: pantry-pm/pantry/packages/action@
|
|
33
|
+
uses: pantry-pm/pantry/packages/action@00f7f8d0f4b166db35d2e1405fdcefd442acd775 # v0.11.68
|
|
34
34
|
with:
|
|
35
35
|
install: 'false'
|
|
36
36
|
|
|
@@ -63,7 +63,7 @@ jobs:
|
|
|
63
63
|
uses: actions/checkout@v4
|
|
64
64
|
|
|
65
65
|
- name: Setup Pantry
|
|
66
|
-
uses: pantry-pm/pantry/packages/action@
|
|
66
|
+
uses: pantry-pm/pantry/packages/action@00f7f8d0f4b166db35d2e1405fdcefd442acd775 # v0.11.68
|
|
67
67
|
with:
|
|
68
68
|
install: 'false'
|
|
69
69
|
|
|
@@ -99,7 +99,7 @@ jobs:
|
|
|
99
99
|
uses: actions/checkout@v4
|
|
100
100
|
|
|
101
101
|
- name: Setup Pantry
|
|
102
|
-
uses: pantry-pm/pantry/packages/action@
|
|
102
|
+
uses: pantry-pm/pantry/packages/action@00f7f8d0f4b166db35d2e1405fdcefd442acd775 # v0.11.68
|
|
103
103
|
with:
|
|
104
104
|
install: 'false'
|
|
105
105
|
|
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
fetch-depth: 0
|
|
22
22
|
|
|
23
23
|
- name: Setup Pantry
|
|
24
|
-
uses: pantry-pm/pantry/packages/action@
|
|
24
|
+
uses: pantry-pm/pantry/packages/action@00f7f8d0f4b166db35d2e1405fdcefd442acd775 # v0.11.68
|
|
25
25
|
with:
|
|
26
26
|
install: 'false'
|
|
27
27
|
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The slice of the VS Code extension API this extension uses.
|
|
3
|
-
*
|
|
4
|
-
* `@types/vscode` is the complete declaration, but it would be the only
|
|
5
|
-
* dependency of a package that otherwise has none, and the extension calls a
|
|
6
|
-
* couple of dozen members. The names and signatures below are copied from
|
|
7
|
-
* `@types/vscode` (engine ^1.93 for the terminal shell-integration API), so
|
|
8
|
-
* swapping this file for the real package later is a deletion, not a rewrite.
|
|
9
|
-
*/
|
|
10
|
-
declare module 'vscode' {
|
|
11
|
-
export interface Disposable {
|
|
12
|
-
dispose: () => unknown
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type Event<T> = (listener: (event: T) => unknown) => Disposable
|
|
16
|
-
|
|
17
|
-
export class Uri {
|
|
18
|
-
static parse(value: string): Uri
|
|
19
|
-
static file(path: string): Uri
|
|
20
|
-
readonly scheme: string
|
|
21
|
-
readonly authority: string
|
|
22
|
-
readonly path: string
|
|
23
|
-
readonly fsPath: string
|
|
24
|
-
toString(skipEncoding?: boolean): string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export enum ViewColumn {
|
|
28
|
-
Active = -1,
|
|
29
|
-
Beside = -2,
|
|
30
|
-
One = 1,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export enum StatusBarAlignment {
|
|
34
|
-
Left = 1,
|
|
35
|
-
Right = 2,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ExtensionContext {
|
|
39
|
-
readonly subscriptions: Disposable[]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface WorkspaceFolder {
|
|
43
|
-
readonly uri: Uri
|
|
44
|
-
readonly name: string
|
|
45
|
-
readonly index: number
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface WorkspaceConfiguration {
|
|
49
|
-
get: <T>(section: string, defaultValue: T) => T
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface ConfigurationChangeEvent {
|
|
53
|
-
affectsConfiguration: (section: string) => boolean
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface FileSystemWatcher extends Disposable {
|
|
57
|
-
readonly onDidCreate: Event<Uri>
|
|
58
|
-
readonly onDidChange: Event<Uri>
|
|
59
|
-
readonly onDidDelete: Event<Uri>
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface TerminalOptions {
|
|
63
|
-
name?: string
|
|
64
|
-
cwd?: string | Uri
|
|
65
|
-
env?: Record<string, string | null | undefined>
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface TerminalExitStatus {
|
|
69
|
-
readonly code: number | undefined
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface TerminalShellExecution {
|
|
73
|
-
read: () => AsyncIterable<string>
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface TerminalShellIntegration {
|
|
77
|
-
executeCommand: (commandLine: string) => TerminalShellExecution
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export interface Terminal {
|
|
81
|
-
readonly name: string
|
|
82
|
-
readonly exitStatus: TerminalExitStatus | undefined
|
|
83
|
-
readonly shellIntegration: TerminalShellIntegration | undefined
|
|
84
|
-
show: (preserveFocus?: boolean) => void
|
|
85
|
-
sendText: (text: string, shouldExecute?: boolean) => void
|
|
86
|
-
dispose: () => void
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface TerminalShellIntegrationChangeEvent {
|
|
90
|
-
readonly terminal: Terminal
|
|
91
|
-
readonly shellIntegration: TerminalShellIntegration
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface TerminalShellExecutionEndEvent {
|
|
95
|
-
readonly terminal: Terminal
|
|
96
|
-
readonly execution: TerminalShellExecution
|
|
97
|
-
readonly exitCode: number | undefined
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface StatusBarItem {
|
|
101
|
-
text: string
|
|
102
|
-
tooltip: string | undefined
|
|
103
|
-
command: string | undefined
|
|
104
|
-
name: string | undefined
|
|
105
|
-
show: () => void
|
|
106
|
-
hide: () => void
|
|
107
|
-
dispose: () => void
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export interface QuickPickItem {
|
|
111
|
-
label: string
|
|
112
|
-
description?: string
|
|
113
|
-
detail?: string
|
|
114
|
-
alwaysShow?: boolean
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export interface QuickPick<T extends QuickPickItem> extends Disposable {
|
|
118
|
-
value: string
|
|
119
|
-
title: string | undefined
|
|
120
|
-
placeholder: string | undefined
|
|
121
|
-
items: readonly T[]
|
|
122
|
-
readonly selectedItems: readonly T[]
|
|
123
|
-
busy: boolean
|
|
124
|
-
matchOnDescription: boolean
|
|
125
|
-
readonly onDidChangeValue: Event<string>
|
|
126
|
-
readonly onDidAccept: Event<void>
|
|
127
|
-
readonly onDidHide: Event<void>
|
|
128
|
-
show: () => void
|
|
129
|
-
hide: () => void
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export interface InputBoxOptions {
|
|
133
|
-
title?: string
|
|
134
|
-
prompt?: string
|
|
135
|
-
placeHolder?: string
|
|
136
|
-
value?: string
|
|
137
|
-
ignoreFocusOut?: boolean
|
|
138
|
-
validateInput?: (value: string) => string | undefined | null
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export interface TextDocument {
|
|
142
|
-
readonly uri: Uri
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export interface TextEditor {
|
|
146
|
-
readonly document: TextDocument
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export namespace window {
|
|
150
|
-
export const activeTextEditor: TextEditor | undefined
|
|
151
|
-
export const terminals: readonly Terminal[]
|
|
152
|
-
export const onDidCloseTerminal: Event<Terminal>
|
|
153
|
-
export const onDidChangeTerminalShellIntegration: Event<TerminalShellIntegrationChangeEvent>
|
|
154
|
-
export const onDidEndTerminalShellExecution: Event<TerminalShellExecutionEndEvent>
|
|
155
|
-
export function createTerminal(options: TerminalOptions): Terminal
|
|
156
|
-
export function createStatusBarItem(id: string, alignment?: StatusBarAlignment, priority?: number): StatusBarItem
|
|
157
|
-
export function createQuickPick<T extends QuickPickItem>(): QuickPick<T>
|
|
158
|
-
export function showInputBox(options?: InputBoxOptions): PromiseLike<string | undefined>
|
|
159
|
-
export function showInformationMessage<T extends string>(message: string, ...items: T[]): PromiseLike<T | undefined>
|
|
160
|
-
export function showWarningMessage<T extends string>(message: string, ...items: T[]): PromiseLike<T | undefined>
|
|
161
|
-
export function showErrorMessage<T extends string>(message: string, ...items: T[]): PromiseLike<T | undefined>
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export namespace workspace {
|
|
165
|
-
export const workspaceFolders: readonly WorkspaceFolder[] | undefined
|
|
166
|
-
export const onDidChangeConfiguration: Event<ConfigurationChangeEvent>
|
|
167
|
-
export function getConfiguration(section?: string): WorkspaceConfiguration
|
|
168
|
-
export function getWorkspaceFolder(uri: Uri): WorkspaceFolder | undefined
|
|
169
|
-
export function createFileSystemWatcher(globPattern: string): FileSystemWatcher
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export namespace commands {
|
|
173
|
-
export function registerCommand(command: string, callback: (...args: any[]) => any): Disposable
|
|
174
|
-
export function executeCommand<T = unknown>(command: string, ...rest: any[]): PromiseLike<T>
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export namespace env {
|
|
178
|
-
export function asExternalUri(target: Uri): PromiseLike<Uri>
|
|
179
|
-
export function openExternal(target: Uri): PromiseLike<boolean>
|
|
180
|
-
}
|
|
181
|
-
}
|