cursedbelt 4.7.0 → 5.0.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.
- package/README.md +36 -0
- package/dist/react/chat/index.d.ts +1 -0
- package/dist/react/chat/index.d.ts.map +1 -1
- package/dist/react/chat/index.js +1 -0
- package/dist/react/chat/index.js.map +1 -1
- package/dist/react/chat/usePresence.d.ts +75 -0
- package/dist/react/chat/usePresence.d.ts.map +1 -0
- package/dist/react/chat/usePresence.js +109 -0
- package/dist/react/chat/usePresence.js.map +1 -0
- package/dist/react/components/SecretInput.d.ts +7 -2
- package/dist/react/components/SecretInput.d.ts.map +1 -1
- package/dist/react/components/SecretInput.js +5 -2
- package/dist/react/components/SecretInput.js.map +1 -1
- package/dist/react/components/TooltipImpl.d.ts.map +1 -1
- package/dist/react/components/TooltipImpl.js +52 -3
- package/dist/react/components/TooltipImpl.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/master-lock/MasterLockDialog.d.ts.map +1 -1
- package/dist/react/master-lock/MasterLockDialog.js +2 -1
- package/dist/react/master-lock/MasterLockDialog.js.map +1 -1
- package/dist/react/master-lock/MasterLockProvider.d.ts +12 -18
- package/dist/react/master-lock/MasterLockProvider.d.ts.map +1 -1
- package/dist/react/master-lock/MasterLockProvider.js +14 -20
- package/dist/react/master-lock/MasterLockProvider.js.map +1 -1
- package/dist/react/media/MediaUploadControl.d.ts +3 -7
- package/dist/react/media/MediaUploadControl.d.ts.map +1 -1
- package/dist/react/media/MediaUploadControl.js +4 -13
- package/dist/react/media/MediaUploadControl.js.map +1 -1
- package/dist/react/media/fileUploadClient.d.ts +0 -8
- package/dist/react/media/fileUploadClient.d.ts.map +1 -1
- package/dist/react/media/fileUploadClient.js +0 -8
- package/dist/react/media/fileUploadClient.js.map +1 -1
- package/dist/react/media/hlsSource.d.ts.map +1 -1
- package/dist/react/media/hlsSource.js +4 -2
- package/dist/react/media/hlsSource.js.map +1 -1
- package/dist/react/media/index.d.ts +0 -4
- package/dist/react/media/index.d.ts.map +1 -1
- package/dist/react/media/index.js +0 -4
- package/dist/react/media/index.js.map +1 -1
- package/dist/react/sessionAuth.d.ts +1 -2
- package/dist/react/sessionAuth.d.ts.map +1 -1
- package/dist/react/sessionAuth.js +2 -3
- package/dist/react/sessionAuth.js.map +1 -1
- package/dist/scripts/guardrailsEnforce.d.ts.map +1 -1
- package/dist/styles-areas/activity-bar.css +1 -1
- package/dist/styles-areas/auth.css +1 -1
- package/dist/styles-areas/charts.css +1 -1
- package/dist/styles-areas/chat.css +1 -1
- package/dist/styles-areas/core.css +1 -1
- package/dist/styles-areas/data-table.css +1 -1
- package/dist/styles-areas/disk-usage.css +1 -1
- package/dist/styles-areas/fields.css +1 -1
- package/dist/styles-areas/master-detail.css +1 -1
- package/dist/styles-areas/master-lock.css +108 -2
- package/dist/styles-areas/media-gallery.css +1 -1
- package/dist/styles-areas/media.css +1 -17
- package/dist/styles-areas/nav.css +1 -1
- package/dist/styles-areas/notifications.css +1 -1
- package/dist/styles-areas/spreadsheet.css +1 -1
- package/dist/styles-areas/stats.css +1 -1
- package/dist/styles-areas/wizard.css +1 -1
- package/dist/styles-areas/workbook-viewer.css +1 -1
- package/dist/styles-utilities.css +0 -16
- package/dist/testing/_noBun.d.ts +2 -0
- package/dist/testing/_noBun.d.ts.map +1 -0
- package/dist/testing/_noBun.js +10 -0
- package/dist/testing/_noBun.js.map +1 -0
- package/package.json +42 -19
- package/scripts/checkAreaStyles.spec.ts +71 -0
- package/scripts/checkAreaStyles.ts +150 -0
- package/scripts/guardrailsEnforce.spec.ts +43 -0
- package/scripts/guardrailsEnforce.ts +46 -1
- package/scripts/styleAreas.ts +1 -2
- package/src/barrelsReachNoOptionalPeer.spec.ts +6 -3
- package/src/bundlerOnlyEntries.spec.ts +101 -0
- package/src/declaredImports.spec.ts +4 -0
- package/src/optionalPeersTable.spec.ts +127 -0
- package/src/react/chat/index.ts +8 -0
- package/src/react/chat/usePresence.spec.tsx +138 -0
- package/src/react/chat/usePresence.ts +185 -0
- package/src/react/components/SecretInput.tsx +12 -1
- package/src/react/components/TooltipImpl.tsx +54 -5
- package/src/react/index.ts +8 -0
- package/src/react/master-lock/MasterLockDialog.tsx +13 -9
- package/src/react/master-lock/MasterLockProvider.spec.tsx +17 -0
- package/src/react/master-lock/MasterLockProvider.tsx +16 -19
- package/src/react/media/MediaUploadControl.tsx +8 -29
- package/src/react/media/fileUploadClient.ts +7 -17
- package/src/react/media/hlsSource.ts +4 -1
- package/src/react/media/index.ts +0 -16
- package/src/react/sessionAuth.ts +2 -3
- package/src/scriptsResolve.spec.ts +66 -0
- package/src/styles-areas/activity-bar.css +1 -1
- package/src/styles-areas/auth.css +1 -1
- package/src/styles-areas/charts.css +1 -1
- package/src/styles-areas/chat.css +1 -1
- package/src/styles-areas/core.css +1 -1
- package/src/styles-areas/data-table.css +1 -1
- package/src/styles-areas/disk-usage.css +1 -1
- package/src/styles-areas/fields.css +1 -1
- package/src/styles-areas/master-detail.css +1 -1
- package/src/styles-areas/master-lock.css +108 -2
- package/src/styles-areas/media-gallery.css +1 -1
- package/src/styles-areas/media.css +1 -17
- package/src/styles-areas/nav.css +1 -1
- package/src/styles-areas/notifications.css +1 -1
- package/src/styles-areas/spreadsheet.css +1 -1
- package/src/styles-areas/stats.css +1 -1
- package/src/styles-areas/wizard.css +1 -1
- package/src/styles-areas/workbook-viewer.css +1 -1
- package/src/styles-utilities.css +0 -16
- package/src/testing/_noBun.ts +12 -0
- package/src/verifyGraph.spec.ts +11 -0
- package/dist/react/media/PrivateIndexView.d.ts +0 -6
- package/dist/react/media/PrivateIndexView.d.ts.map +0 -1
- package/dist/react/media/PrivateIndexView.js +0 -44
- package/dist/react/media/PrivateIndexView.js.map +0 -1
- package/dist/react/media/PrivateModeBadge.d.ts +0 -17
- package/dist/react/media/PrivateModeBadge.d.ts.map +0 -1
- package/dist/react/media/PrivateModeBadge.js +0 -24
- package/dist/react/media/PrivateModeBadge.js.map +0 -1
- package/dist/react/media/privateClient.d.ts +0 -34
- package/dist/react/media/privateClient.d.ts.map +0 -1
- package/dist/react/media/privateClient.js +0 -36
- package/dist/react/media/privateClient.js.map +0 -1
- package/dist/react/media/usePrivateUnlock.d.ts +0 -25
- package/dist/react/media/usePrivateUnlock.d.ts.map +0 -1
- package/dist/react/media/usePrivateUnlock.js +0 -68
- package/dist/react/media/usePrivateUnlock.js.map +0 -1
- package/src/react/media/PrivateIndexView.tsx +0 -113
- package/src/react/media/PrivateModeBadge.tsx +0 -50
- package/src/react/media/privateClient.spec.ts +0 -113
- package/src/react/media/privateClient.ts +0 -82
- package/src/react/media/usePrivateUnlock.ts +0 -132
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Upload } from 'lucide-react';
|
|
2
2
|
import { type ReactNode, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Button } from '../components/Button.js';
|
|
4
|
-
import { Checkbox } from '../components/Checkbox.js';
|
|
5
4
|
import { Input } from '../components/Input.js';
|
|
6
5
|
import { cn } from '../lib/cn.js';
|
|
7
6
|
import { createFileUploadClient } from './fileUploadClient.js';
|
|
@@ -12,8 +11,8 @@ import { createFileUploadClient } from './fileUploadClient.js';
|
|
|
12
11
|
// no ENGINE-model consumer, but three shipping plugins render it
|
|
13
12
|
// (`plugin-photo-gallery`, `plugin-video-gallery`, `plugin-media-gallery`), so
|
|
14
13
|
// deleting it would break them. It speaks the legacy chunked `/_files` protocol
|
|
15
|
-
// (`createFileUploadClient` + `createFilesStack`), including the tag list
|
|
16
|
-
//
|
|
14
|
+
// (`createFileUploadClient` + `createFilesStack`), including the tag list. (Its private
|
|
15
|
+
// mode went with the server's private-media module — task 108.)
|
|
17
16
|
//
|
|
18
17
|
// The ENGINE model uploads through `POST /api/asset/vault/upload` — raw bytes,
|
|
19
18
|
// `x-cc-filename`, checksum computed while streaming, content-addressed dedupe —
|
|
@@ -25,19 +24,16 @@ import { createFileUploadClient } from './fileUploadClient.js';
|
|
|
25
24
|
//
|
|
26
25
|
// ── Media upload control ─────────────────────────────────────────────────────────
|
|
27
26
|
// The one "⬆ Upload" affordance media galleries share: a disclosure button opening a
|
|
28
|
-
// compact form — comma-separated tags
|
|
29
|
-
//
|
|
30
|
-
// via X-Unlock-Token). Consumers own only WHERE it sits and what happens after.
|
|
27
|
+
// compact form — comma-separated tags and a file picker — feeding the shared upload client
|
|
28
|
+
// (chunked-aware). Consumers own only WHERE it sits and what happens after.
|
|
31
29
|
|
|
32
30
|
export interface MediaUploadControlProps {
|
|
33
31
|
/** File-picker accept filter, e.g. "video/*" or "image/*". */
|
|
34
32
|
accept: string;
|
|
35
33
|
/** Mount prefix of the host's file routes (createFilesStack filesBasePath). */
|
|
36
34
|
basePath: string;
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
/** After every successful batch: `wasPrivate` says which list to refresh. */
|
|
40
|
-
onUploaded: (result: { wasPrivate: boolean }) => void;
|
|
35
|
+
/** After every successful batch. */
|
|
36
|
+
onUploaded: () => void;
|
|
41
37
|
label?: ReactNode;
|
|
42
38
|
className?: string;
|
|
43
39
|
}
|
|
@@ -45,14 +41,12 @@ export interface MediaUploadControlProps {
|
|
|
45
41
|
export function MediaUploadControl({
|
|
46
42
|
accept,
|
|
47
43
|
basePath,
|
|
48
|
-
privateToken = null,
|
|
49
44
|
onUploaded,
|
|
50
45
|
label = 'Upload',
|
|
51
46
|
className,
|
|
52
47
|
}: MediaUploadControlProps) {
|
|
53
48
|
const [open, setOpen] = useState(false);
|
|
54
49
|
const [tags, setTags] = useState('');
|
|
55
|
-
const [asPrivate, setAsPrivate] = useState(false);
|
|
56
50
|
const [busy, setBusy] = useState(false);
|
|
57
51
|
const [error, setError] = useState<string | null>(null);
|
|
58
52
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
@@ -62,19 +56,13 @@ export function MediaUploadControl({
|
|
|
62
56
|
const uploadFiles = async (list: FileList) => {
|
|
63
57
|
setBusy(true);
|
|
64
58
|
setError(null);
|
|
65
|
-
const wantPrivate = asPrivate && !!privateToken;
|
|
66
59
|
const parsedTags = tags
|
|
67
60
|
.split(',')
|
|
68
61
|
.map((t) => t.trim())
|
|
69
62
|
.filter(Boolean);
|
|
70
63
|
try {
|
|
71
64
|
for (const file of Array.from(list)) {
|
|
72
|
-
const res =
|
|
73
|
-
? await client.uploadPrivate(file, {
|
|
74
|
-
tags: parsedTags,
|
|
75
|
-
unlockToken: privateToken,
|
|
76
|
-
})
|
|
77
|
-
: await client.uploadAuto(file, { tags: parsedTags });
|
|
65
|
+
const res = await client.uploadAuto(file, { tags: parsedTags });
|
|
78
66
|
if (!res.ok) {
|
|
79
67
|
setError(res.error);
|
|
80
68
|
return;
|
|
@@ -82,8 +70,7 @@ export function MediaUploadControl({
|
|
|
82
70
|
}
|
|
83
71
|
setOpen(false);
|
|
84
72
|
setTags('');
|
|
85
|
-
|
|
86
|
-
onUploaded({ wasPrivate: wantPrivate });
|
|
73
|
+
onUploaded();
|
|
87
74
|
} finally {
|
|
88
75
|
setBusy(false);
|
|
89
76
|
}
|
|
@@ -113,14 +100,6 @@ export function MediaUploadControl({
|
|
|
113
100
|
className='max-w-[200px]'
|
|
114
101
|
aria-label='Upload tags'
|
|
115
102
|
/>
|
|
116
|
-
{privateToken ? (
|
|
117
|
-
<Checkbox
|
|
118
|
-
checked={asPrivate}
|
|
119
|
-
onCheckedChange={(checked) => setAsPrivate(checked === true)}
|
|
120
|
-
disabled={busy}
|
|
121
|
-
label='Private'
|
|
122
|
-
/>
|
|
123
|
-
) : null}
|
|
124
103
|
<Button
|
|
125
104
|
size='sm'
|
|
126
105
|
disabled={busy}
|
|
@@ -4,8 +4,13 @@ import { sessionAuthHeaders } from '../sessionAuth.js';
|
|
|
4
4
|
// ── File-upload client (hook-free) ───────────────────────────────────────────────
|
|
5
5
|
// The one client for mountFileRoutes' upload edge, shared by every consumer (the files
|
|
6
6
|
// plugin, gallery upload buttons, the video editor's save-back) so the header protocol
|
|
7
|
-
// (X-Filename / X-Tags
|
|
8
|
-
//
|
|
7
|
+
// (X-Filename / X-Tags) and the chunked-vs-streamed decision live in exactly one place.
|
|
8
|
+
// Hook-free: plugins hold no upload state.
|
|
9
|
+
//
|
|
10
|
+
// 🔴 There is no private upload any more (task 108, 2026-09-23). `uploadPrivate` PUT to
|
|
11
|
+
// `/_files/upload-private`, a route `cursedbelt-server` deleted with its private-media module
|
|
12
|
+
// (task 00-urgent-24), so the method was a 404 waiting for a caller. It went, with the rest of
|
|
13
|
+
// the private-media client tier, rather than staying as a method that cannot succeed.
|
|
9
14
|
|
|
10
15
|
/** The FileRecord subset consumers act on after an upload (full shape: server files/types). */
|
|
11
16
|
export type UploadedFile = {
|
|
@@ -35,12 +40,6 @@ export interface FileUploadClientConfig {
|
|
|
35
40
|
export interface FileUploadClient {
|
|
36
41
|
/** Streamed single-PUT public upload. */
|
|
37
42
|
upload(file: File | Blob, opts?: { name?: string; tags?: string[] }): Promise<UploadOutcome>;
|
|
38
|
-
/** Private (encrypted) upload — pass the unlock token of the already-unlocked session, or a
|
|
39
|
-
* password for a deniable set; neither ⇒ the standard server-key set. */
|
|
40
|
-
uploadPrivate(
|
|
41
|
-
file: File | Blob,
|
|
42
|
-
opts?: { name?: string; tags?: string[]; unlockToken?: string | null; password?: string },
|
|
43
|
-
): Promise<UploadOutcome>;
|
|
44
43
|
/** Overwrite an existing file's bytes in place (same id; tags/collections survive). */
|
|
45
44
|
replace(
|
|
46
45
|
fileId: string,
|
|
@@ -163,15 +162,6 @@ export function createFileUploadClient(cfg: FileUploadClientConfig = {}): FileUp
|
|
|
163
162
|
return {
|
|
164
163
|
upload,
|
|
165
164
|
|
|
166
|
-
async uploadPrivate(file, opts) {
|
|
167
|
-
const headers = commonHeaders(file, opts);
|
|
168
|
-
if (opts?.unlockToken) headers['X-Unlock-Token'] = opts.unlockToken;
|
|
169
|
-
else if (opts?.password) headers['X-Private-Password'] = opts.password;
|
|
170
|
-
return outcome(
|
|
171
|
-
await doFetch(`${base}/upload-private`, { method: 'PUT', headers, body: file }),
|
|
172
|
-
);
|
|
173
|
-
},
|
|
174
|
-
|
|
175
165
|
async replace(fileId, file, opts) {
|
|
176
166
|
return outcome(
|
|
177
167
|
await doFetch(`${base}/replace/${fileId}`, {
|
|
@@ -339,7 +339,10 @@ export function attachHlsSource(
|
|
|
339
339
|
// guidance: calling `recoverMediaError()` twice for the same stall recovers
|
|
340
340
|
// nothing, and the audio-codec swap is what clears the case that keeps recurring.
|
|
341
341
|
if (attempt === 0) hls.recoverMediaError();
|
|
342
|
-
else
|
|
342
|
+
else {
|
|
343
|
+
hls.swapAudioCodec?.();
|
|
344
|
+
hls.recoverMediaError();
|
|
345
|
+
}
|
|
343
346
|
return;
|
|
344
347
|
}
|
|
345
348
|
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
|
package/src/react/media/index.ts
CHANGED
|
@@ -145,15 +145,6 @@ export {
|
|
|
145
145
|
probeMediaDurationFromUrl,
|
|
146
146
|
useMediaDuration,
|
|
147
147
|
} from './mediaProbe.js';
|
|
148
|
-
export { PrivateIndexView } from './PrivateIndexView.js';
|
|
149
|
-
export { PrivateModeBadge, type PrivateModeBadgeProps } from './PrivateModeBadge.js';
|
|
150
|
-
export {
|
|
151
|
-
type PrivateClientConfig,
|
|
152
|
-
privateFileUrlWithToken,
|
|
153
|
-
privateHlsUrlWithToken,
|
|
154
|
-
revealPrivateWithPassword,
|
|
155
|
-
revealPrivateWithToken,
|
|
156
|
-
} from './privateClient.js';
|
|
157
148
|
export type {
|
|
158
149
|
ImageEditorMode,
|
|
159
150
|
ImageEditorOperation,
|
|
@@ -168,13 +159,6 @@ export type {
|
|
|
168
159
|
export { type UseAudioPeaksOptions, useAudioPeaks } from './useAudioPeaks.js';
|
|
169
160
|
export { useIntersectionObserver } from './useIntersectionObserver.js';
|
|
170
161
|
export { useObjectUrl } from './useObjectUrl.js';
|
|
171
|
-
export {
|
|
172
|
-
type PrivateIndexRow,
|
|
173
|
-
type PrivateUnlock,
|
|
174
|
-
type RevealedItem,
|
|
175
|
-
type UsePrivateUnlockOptions,
|
|
176
|
-
usePrivateUnlock,
|
|
177
|
-
} from './usePrivateUnlock.js';
|
|
178
162
|
// Attaching an adaptive ladder to a bare `<video>` — native HLS first, hls.js second, the
|
|
179
163
|
// progressive remux always. Exported because three surfaces in the fleet drive a plain
|
|
180
164
|
// element rather than Vidstack and each was carrying its own copy of the decision.
|
package/src/react/sessionAuth.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ── Session auth headers (hook-free) ────────────────────────────────────────
|
|
2
2
|
// One source of truth for "turn the browser session into a Bearer header". Plugins
|
|
3
|
-
// that call guarded endpoints (uploads,
|
|
3
|
+
// that call guarded endpoints (uploads, RPC over fetch)
|
|
4
4
|
// all need the same header shape; before this they each re-rolled the cookie read.
|
|
5
5
|
//
|
|
6
6
|
// NOTE (genapp-34): a generated app's `session` cookie is now `HttpOnly`, so this
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* Shaped as a plain function (not a hook) so it can be passed straight to helpers
|
|
21
21
|
* that expect an `authHeaders: () => Record<string, string>` callback
|
|
22
|
-
* (`
|
|
23
|
-
* `fetch` init's headers.
|
|
22
|
+
* (`createFileUploadClient`'s, for one) and spread into a `fetch` init's headers.
|
|
24
23
|
*/
|
|
25
24
|
export function sessionAuthHeaders(): Record<string, string> {
|
|
26
25
|
const token =
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every `bun run <x>` a script calls, and every command the app manifest names, is a script
|
|
3
|
+
* that EXISTS in this `package.json`.
|
|
4
|
+
*
|
|
5
|
+
* 🔴 Task 102, 2026-09-18: `done:serial` was `typecheck && lint && test && build`, and there was
|
|
6
|
+
* no `lint` script — so it had never once reached `test` or `build`, and the 31 lint errors a
|
|
7
|
+
* `lint` would have shown sat unseen. `format` was named in `cursed.app.extraCommands` too.
|
|
8
|
+
* Neither was in the gate, which is exactly why nobody noticed; this spec is in the gate.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, expect, it } from 'bun:test';
|
|
11
|
+
import pkg from '../package.json';
|
|
12
|
+
|
|
13
|
+
const scripts = (pkg as { scripts: Record<string, string> }).scripts;
|
|
14
|
+
|
|
15
|
+
/** The script names a command line invokes through `bun run` / `npm run`. */
|
|
16
|
+
export function calledScripts(command: string): string[] {
|
|
17
|
+
const out: string[] = [];
|
|
18
|
+
for (const m of command.matchAll(/\b(?:bun|npm|pnpm|yarn) run\s+([A-Za-z0-9:_./-]+)/g)) {
|
|
19
|
+
// A path (`bun run scripts/x.ts`) is a file, not a script name.
|
|
20
|
+
if (m[1] && !m[1].includes('/') && !/\.[cm]?[jt]sx?$/.test(m[1])) out.push(m[1]);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('package.json scripts resolve', () => {
|
|
26
|
+
it('reads `bun run <name>` and skips `bun run <file>`', () => {
|
|
27
|
+
expect(calledScripts('bun run typecheck && bun run lint && bun run scripts/gate.ts')).toEqual([
|
|
28
|
+
'typecheck',
|
|
29
|
+
'lint',
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('🔴 fails on a script that calls one that is not there — the task-102 shape', () => {
|
|
34
|
+
const fake = { 'done:serial': 'bun run typecheck && bun run lint', typecheck: 'tsc' };
|
|
35
|
+
const dangling = Object.values(fake)
|
|
36
|
+
.flatMap(calledScripts)
|
|
37
|
+
.filter((name) => !(name in fake));
|
|
38
|
+
expect(dangling).toEqual(['lint']);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('every `bun run <script>` inside a script names a script that exists', () => {
|
|
42
|
+
const dangling: string[] = [];
|
|
43
|
+
for (const [name, command] of Object.entries(scripts)) {
|
|
44
|
+
for (const called of calledScripts(command)) {
|
|
45
|
+
if (!(called in scripts)) dangling.push(`${name} → ${called}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
expect(dangling).toEqual([]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('every command the `cursed.app` manifest names is a script', () => {
|
|
52
|
+
const app = (pkg as { cursed?: { app?: Record<string, unknown> } }).cursed?.app ?? {};
|
|
53
|
+
const named: string[] = [];
|
|
54
|
+
for (const key of ['commands', 'extraCommands']) {
|
|
55
|
+
const block = app[key] as Record<string, string> | undefined;
|
|
56
|
+
if (block) named.push(...Object.values(block));
|
|
57
|
+
}
|
|
58
|
+
expect(named.length).toBeGreaterThan(0);
|
|
59
|
+
expect(named.filter((n) => !(n in scripts))).toEqual([]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('every gate stage is a script', () => {
|
|
63
|
+
const stages = (pkg as { gate?: { stages?: { script: string }[] } }).gate?.stages ?? [];
|
|
64
|
+
expect(stages.map((s) => s.script).filter((n) => !(n in scripts))).toEqual([]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 71 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 303 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 462 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 388 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
15
15
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
16
|
-
* when this file is stale.
|
|
16
|
+
* when this file is stale. 5197 candidate(s) scanned.
|
|
17
17
|
*
|
|
18
18
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
19
19
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 1350 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 289 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 616 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 198 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,12 +15,118 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 189 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
22
22
|
* import closures rather than a hand-written list, is scripts/styleAreas.ts.
|
|
23
23
|
*/
|
|
24
24
|
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
25
|
+
@layer properties;
|
|
25
26
|
@layer theme, base, components, utilities;
|
|
26
|
-
@layer utilities
|
|
27
|
+
@layer utilities {
|
|
28
|
+
.self-stretch {
|
|
29
|
+
align-self: stretch;
|
|
30
|
+
}
|
|
31
|
+
.focus-within\:border-field-ring:focus-within {
|
|
32
|
+
border-color: var(--field-ring);
|
|
33
|
+
}
|
|
34
|
+
.focus-within\:ring-2:focus-within {
|
|
35
|
+
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
36
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
37
|
+
}
|
|
38
|
+
.focus-within\:ring-field-ring\/30:focus-within {
|
|
39
|
+
--tw-ring-color: var(--field-ring);
|
|
40
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
41
|
+
--tw-ring-color: color-mix(in oklab, var(--field-ring) 30%, transparent);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
.has-\[\[aria-invalid\=true\]\]\:border-field-error:has(:is([aria-invalid=true])) {
|
|
45
|
+
border-color: var(--field-error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
@property --tw-shadow {
|
|
49
|
+
syntax: "*";
|
|
50
|
+
inherits: false;
|
|
51
|
+
initial-value: 0 0 #0000;
|
|
52
|
+
}
|
|
53
|
+
@property --tw-shadow-color {
|
|
54
|
+
syntax: "*";
|
|
55
|
+
inherits: false;
|
|
56
|
+
}
|
|
57
|
+
@property --tw-shadow-alpha {
|
|
58
|
+
syntax: "<percentage>";
|
|
59
|
+
inherits: false;
|
|
60
|
+
initial-value: 100%;
|
|
61
|
+
}
|
|
62
|
+
@property --tw-inset-shadow {
|
|
63
|
+
syntax: "*";
|
|
64
|
+
inherits: false;
|
|
65
|
+
initial-value: 0 0 #0000;
|
|
66
|
+
}
|
|
67
|
+
@property --tw-inset-shadow-color {
|
|
68
|
+
syntax: "*";
|
|
69
|
+
inherits: false;
|
|
70
|
+
}
|
|
71
|
+
@property --tw-inset-shadow-alpha {
|
|
72
|
+
syntax: "<percentage>";
|
|
73
|
+
inherits: false;
|
|
74
|
+
initial-value: 100%;
|
|
75
|
+
}
|
|
76
|
+
@property --tw-ring-color {
|
|
77
|
+
syntax: "*";
|
|
78
|
+
inherits: false;
|
|
79
|
+
}
|
|
80
|
+
@property --tw-ring-shadow {
|
|
81
|
+
syntax: "*";
|
|
82
|
+
inherits: false;
|
|
83
|
+
initial-value: 0 0 #0000;
|
|
84
|
+
}
|
|
85
|
+
@property --tw-inset-ring-color {
|
|
86
|
+
syntax: "*";
|
|
87
|
+
inherits: false;
|
|
88
|
+
}
|
|
89
|
+
@property --tw-inset-ring-shadow {
|
|
90
|
+
syntax: "*";
|
|
91
|
+
inherits: false;
|
|
92
|
+
initial-value: 0 0 #0000;
|
|
93
|
+
}
|
|
94
|
+
@property --tw-ring-inset {
|
|
95
|
+
syntax: "*";
|
|
96
|
+
inherits: false;
|
|
97
|
+
}
|
|
98
|
+
@property --tw-ring-offset-width {
|
|
99
|
+
syntax: "<length>";
|
|
100
|
+
inherits: false;
|
|
101
|
+
initial-value: 0px;
|
|
102
|
+
}
|
|
103
|
+
@property --tw-ring-offset-color {
|
|
104
|
+
syntax: "*";
|
|
105
|
+
inherits: false;
|
|
106
|
+
initial-value: #fff;
|
|
107
|
+
}
|
|
108
|
+
@property --tw-ring-offset-shadow {
|
|
109
|
+
syntax: "*";
|
|
110
|
+
inherits: false;
|
|
111
|
+
initial-value: 0 0 #0000;
|
|
112
|
+
}
|
|
113
|
+
@layer properties {
|
|
114
|
+
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
|
115
|
+
*, ::before, ::after, ::backdrop {
|
|
116
|
+
--tw-shadow: 0 0 #0000;
|
|
117
|
+
--tw-shadow-color: initial;
|
|
118
|
+
--tw-shadow-alpha: 100%;
|
|
119
|
+
--tw-inset-shadow: 0 0 #0000;
|
|
120
|
+
--tw-inset-shadow-color: initial;
|
|
121
|
+
--tw-inset-shadow-alpha: 100%;
|
|
122
|
+
--tw-ring-color: initial;
|
|
123
|
+
--tw-ring-shadow: 0 0 #0000;
|
|
124
|
+
--tw-inset-ring-color: initial;
|
|
125
|
+
--tw-inset-ring-shadow: 0 0 #0000;
|
|
126
|
+
--tw-ring-inset: initial;
|
|
127
|
+
--tw-ring-offset-width: 0px;
|
|
128
|
+
--tw-ring-offset-color: #fff;
|
|
129
|
+
--tw-ring-offset-shadow: 0 0 #0000;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 2159 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 2777 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -156,9 +156,6 @@
|
|
|
156
156
|
border-block-style: var(--tw-border-style);
|
|
157
157
|
border-block-width: 2px;
|
|
158
158
|
}
|
|
159
|
-
.border-\[color\:var\(--border-strong\)\] {
|
|
160
|
-
border-color: var(--border-strong);
|
|
161
|
-
}
|
|
162
159
|
.border-accent {
|
|
163
160
|
border-color: var(--accent);
|
|
164
161
|
}
|
|
@@ -171,12 +168,6 @@
|
|
|
171
168
|
border-color: color-mix(in oklab, var(--color-white) 90%, transparent);
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
|
-
.bg-\[color\:color-mix\(in_srgb\,var\(--accent-solid\)_8\%\,transparent\)\] {
|
|
175
|
-
background-color: var(--accent-solid);
|
|
176
|
-
@supports (color: color-mix(in lab, red, red)) {
|
|
177
|
-
background-color: color-mix(in srgb,var(--accent-solid) 8%,transparent);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
171
|
.bg-accent\/15 {
|
|
181
172
|
background-color: var(--accent);
|
|
182
173
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -283,9 +274,6 @@
|
|
|
283
274
|
.text-\[color\:var\(--accent\)\] {
|
|
284
275
|
color: var(--accent);
|
|
285
276
|
}
|
|
286
|
-
.text-\[color\:var\(--muted-foreground\)\] {
|
|
287
|
-
color: var(--muted-foreground);
|
|
288
|
-
}
|
|
289
277
|
.accent-white {
|
|
290
278
|
accent-color: var(--color-white);
|
|
291
279
|
}
|
|
@@ -322,10 +310,6 @@
|
|
|
322
310
|
.group-focus-within\:opacity-100:is(:where(.group):focus-within *) {
|
|
323
311
|
opacity: 100%;
|
|
324
312
|
}
|
|
325
|
-
.last\:border-b-0:last-child {
|
|
326
|
-
border-bottom-style: var(--tw-border-style);
|
|
327
|
-
border-bottom-width: 0px;
|
|
328
|
-
}
|
|
329
313
|
.focus-within\:opacity-100:focus-within {
|
|
330
314
|
opacity: 100%;
|
|
331
315
|
}
|
package/src/styles-areas/nav.css
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 799 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 231 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 165 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 360 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 392 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* An app that imports every area gets exactly what `cursedbelt/styles-utilities.css`
|
|
17
17
|
* emits — proved rule by rule in src/stylesAreas.spec.ts, which is also what fails
|
|
18
|
-
* when this file is stale.
|
|
18
|
+
* when this file is stale. 246 candidate(s) scanned.
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
package/src/styles-utilities.css
CHANGED
|
@@ -1591,9 +1591,6 @@
|
|
|
1591
1591
|
--tw-border-style: solid;
|
|
1592
1592
|
border-style: solid;
|
|
1593
1593
|
}
|
|
1594
|
-
.border-\[color\:var\(--border-strong\)\] {
|
|
1595
|
-
border-color: var(--border-strong);
|
|
1596
|
-
}
|
|
1597
1594
|
.border-\[var\(--border\)\] {
|
|
1598
1595
|
border-color: var(--border);
|
|
1599
1596
|
}
|
|
@@ -1741,12 +1738,6 @@
|
|
|
1741
1738
|
.border-l-warning {
|
|
1742
1739
|
border-left-color: var(--warning);
|
|
1743
1740
|
}
|
|
1744
|
-
.bg-\[color\:color-mix\(in_srgb\,var\(--accent-solid\)_8\%\,transparent\)\] {
|
|
1745
|
-
background-color: var(--accent-solid);
|
|
1746
|
-
@supports (color: color-mix(in lab, red, red)) {
|
|
1747
|
-
background-color: color-mix(in srgb,var(--accent-solid) 8%,transparent);
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
1741
|
.bg-\[var\(--accent\)\]\/12 {
|
|
1751
1742
|
background-color: var(--accent);
|
|
1752
1743
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -2626,9 +2617,6 @@
|
|
|
2626
2617
|
.text-\[color\:var\(--accent\)\] {
|
|
2627
2618
|
color: var(--accent);
|
|
2628
2619
|
}
|
|
2629
|
-
.text-\[color\:var\(--muted-foreground\)\] {
|
|
2630
|
-
color: var(--muted-foreground);
|
|
2631
|
-
}
|
|
2632
2620
|
.text-\[var\(--danger\)\] {
|
|
2633
2621
|
color: var(--danger);
|
|
2634
2622
|
}
|
|
@@ -3299,10 +3287,6 @@
|
|
|
3299
3287
|
border-right-style: var(--tw-border-style);
|
|
3300
3288
|
border-right-width: 0px;
|
|
3301
3289
|
}
|
|
3302
|
-
.last\:border-b-0:last-child {
|
|
3303
|
-
border-bottom-style: var(--tw-border-style);
|
|
3304
|
-
border-bottom-width: 0px;
|
|
3305
|
-
}
|
|
3306
3290
|
.last\:pr-1:last-child {
|
|
3307
3291
|
padding-right: var(--spacing);
|
|
3308
3292
|
}
|