@stacksjs/defaults 0.75.266 → 0.75.268
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-chat/SKILL.md +32 -0
- package/ai/skills/stacks-native/CATALOG.md +4 -4
- package/app/Models/PersonalAccessToken.ts +8 -0
- package/functions/dashboard-dates.test.ts +44 -0
- package/functions/dashboard-dates.ts +22 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +4 -4
- package/resources/components/Dashboard/UI/Table.stx +4 -17
|
@@ -508,6 +508,38 @@ History is chronological, with `has_more` and a `before` message-id cursor.
|
|
|
508
508
|
Receipts acknowledge only messages through the id actually displayed.
|
|
509
509
|
`MessagingError.status` provides safe HTTP statuses for application handlers.
|
|
510
510
|
|
|
511
|
+
### Attachments
|
|
512
|
+
|
|
513
|
+
`send(id, body, retryKey, attachments?)` records files the application has
|
|
514
|
+
already stored. The trait keeps a reference, never bytes: `file` is the
|
|
515
|
+
application's own name for the upload (a disk path, a bucket key, an id), and
|
|
516
|
+
`type`, `size`, `width` and `height` are optional. Resolving and authorizing
|
|
517
|
+
the file stays with the application, so a disk, a bucket and a CDN look the
|
|
518
|
+
same from here.
|
|
519
|
+
|
|
520
|
+
```ts
|
|
521
|
+
import type { DirectMessageAttachment } from '@stacksjs/chat'
|
|
522
|
+
|
|
523
|
+
const photo: DirectMessageAttachment = { file: upload.key, type: 'image/jpeg', size: upload.size, width: 1200, height: 900 }
|
|
524
|
+
await messenger.send(thread.id, '', retryKey, [photo])
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
- A photo with no caption is a message: `body` may be empty when there is at
|
|
528
|
+
least one attachment, and only then.
|
|
529
|
+
- `message.attachments` is always an array, `[]` for text. Rows written before
|
|
530
|
+
the column existed read as `[]`.
|
|
531
|
+
- A retry key covers the attachments too. The same key with a different file
|
|
532
|
+
is a different message and returns 409, rather than silently keeping the
|
|
533
|
+
first photo.
|
|
534
|
+
- At most 10 attachments, 4000 characters once serialised. Keys the trait does
|
|
535
|
+
not know are dropped, so the column cannot become a second message body.
|
|
536
|
+
- The column is `chat_messages.attachments`, added by `buddy migrate` to a
|
|
537
|
+
database created before it. A database that has not migrated yet still sends
|
|
538
|
+
text.
|
|
539
|
+
- Notification previews are the application's to word: `onMessageSent`
|
|
540
|
+
receives the message with its attachments, so a photo with no caption can
|
|
541
|
+
read as "Sent a photo" rather than as an empty line.
|
|
542
|
+
|
|
511
543
|
For the UI, STX ships `ChatInbox`, `ChatMessage`, and `ChatUnreadBadge` in
|
|
512
544
|
`@stacksjs/components`. Browser stores import `createChat` from
|
|
513
545
|
`@stacksjs/components/chat` and inject their authenticated HTTP transport.
|
|
@@ -18,7 +18,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
18
18
|
| `@stacksjs/api` | [`stacks-api`](../stacks-api/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/index.ts) | 9 |
|
|
19
19
|
| `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 6 |
|
|
20
20
|
| `@stacksjs/audio` | [`stacks-audio`](../stacks-audio/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/audio/src/index.ts) | 2 |
|
|
21
|
-
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) |
|
|
21
|
+
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 120 |
|
|
22
22
|
| `@stacksjs/browser` | [`stacks-browser`](../stacks-browser/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser/src/index.ts) | 8 |
|
|
23
23
|
| `@stacksjs/browser-extension` | [`stacks-browser-extension`](../stacks-browser-extension/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser-extension/src/index.ts) | 7 |
|
|
24
24
|
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 164 |
|
|
@@ -65,7 +65,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
65
65
|
| `@stacksjs/newsletter` | [`stacks-newsletter`](../stacks-newsletter/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/index.ts) | 7 |
|
|
66
66
|
| `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 16 |
|
|
67
67
|
| `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
|
|
68
|
-
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) |
|
|
68
|
+
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 72 |
|
|
69
69
|
| `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
|
|
70
70
|
| `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 13 |
|
|
71
71
|
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 28 |
|
|
@@ -185,7 +185,7 @@ Declared runtime exports: `DEFAULT_ROLE_PACKS`, `createBqbRbacStore`, `generateT
|
|
|
185
185
|
|
|
186
186
|
Local source modules: [src/authentication.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authentication.ts), [src/authenticator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authenticator.ts), [src/authorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authorizable.ts), [src/browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/client.ts), [src/cookie-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/cookie-auth.ts), [src/credential-user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/credential-user.ts), [src/email-verification.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/email-verification.ts), [src/gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/gate.ts), [src/magic-link.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/magic-link.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/middleware.ts), [src/oauth-authorization-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-codes.ts), [src/oauth-authorization-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-endpoint.ts), [src/oauth-authorization-requests.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-requests.ts), [src/oauth-authorization-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-response.ts), [src/oauth-authorization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization.ts), [src/oauth-browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-browser-session.ts), [src/oauth-client-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-client-registration.ts), [src/oauth-consent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-consent.ts), [src/oauth-delegated-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-delegated-access.ts), [src/oauth-dynamic-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-dynamic-registration.ts), [src/oauth-grants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-grants.ts), [src/oauth-introspection.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-introspection.ts), [src/oauth-metadata.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-metadata.ts), [src/oauth-pkce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pkce.ts), [src/oauth-protected-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-protected-resource.ts), [src/oauth-provider.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-provider.ts), [src/oauth-pruning.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pruning.ts), [src/oauth-revocation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-revocation.ts), [src/oauth-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-server.ts), [src/oauth-token-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-endpoint.ts), [src/oauth-token-exchange.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-exchange.ts), [src/oauth-token-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-request.ts), [src/oauth-token-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-response.ts), [src/page-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/page-gate.ts), [src/passkey.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkey.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkeys.ts), [src/password/reset.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset.ts), [src/permissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/permissions.ts), [src/policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/policy.ts), [src/rate-limiter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rate-limiter.ts), [src/rbac-seed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-seed.ts), [src/rbac-store-bqb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-store-bqb.ts), [src/rbac.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac.ts), [src/referrals.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/referrals.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/register.ts), [src/request-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/request-token.ts), [src/session-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-auth.ts), [src/session-handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-handoff.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/socials.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/team.ts), [src/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/tokens.ts), [src/two-factor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor.ts), [src/user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/user.ts).
|
|
187
187
|
|
|
188
|
-
Evidence directory: [
|
|
188
|
+
Evidence directory: [120 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
189
189
|
|
|
190
190
|
### @stacksjs/browser
|
|
191
191
|
|
|
@@ -633,7 +633,7 @@ Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`
|
|
|
633
633
|
|
|
634
634
|
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
635
635
|
|
|
636
|
-
Evidence directory: [
|
|
636
|
+
Evidence directory: [72 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
637
637
|
|
|
638
638
|
### @stacksjs/pagination
|
|
639
639
|
|
|
@@ -162,9 +162,17 @@ export default defineModel({
|
|
|
162
162
|
*/
|
|
163
163
|
|
|
164
164
|
/** Legacy owner column, written as a copy of `tokenable_id`. */
|
|
165
|
+
/**
|
|
166
|
+
* The legacy owner column, a copy of `tokenableId` kept for installs that
|
|
167
|
+
* predate the pair. `ensureAuthTables()` gives it no constraint, since a
|
|
168
|
+
* token can belong to an author as well as a user, so it is not a foreign
|
|
169
|
+
* key. Without saying so, convention inferred `users.id` from the name and
|
|
170
|
+
* a fresh app's first `buddy doctor` failed on it.
|
|
171
|
+
*/
|
|
165
172
|
userId: {
|
|
166
173
|
order: 10,
|
|
167
174
|
guarded: true,
|
|
175
|
+
foreignKey: false,
|
|
168
176
|
validation: {
|
|
169
177
|
rule: schema.number(),
|
|
170
178
|
},
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Run `parseDashboardDate` in a process pinned to `zone`, since a calendar
|
|
5
|
+
* date only goes wrong west of UTC and a test process's zone is fixed at
|
|
6
|
+
* start-up.
|
|
7
|
+
*/
|
|
8
|
+
async function inZone(zone: string, expression: string): Promise<string> {
|
|
9
|
+
const child = Bun.spawn([process.execPath, '--no-env-file', '-e', `
|
|
10
|
+
const { parseDashboardDate } = await import(${JSON.stringify(`${import.meta.dir}/dashboard-dates.ts`)})
|
|
11
|
+
console.log(${expression})
|
|
12
|
+
`], { env: { ...process.env, TZ: zone }, stdout: 'pipe', stderr: 'pipe' })
|
|
13
|
+
const [code, out, err] = await Promise.all([child.exited, new Response(child.stdout).text(), new Response(child.stderr).text()])
|
|
14
|
+
expect(code, err).toBe(0)
|
|
15
|
+
return out.trim()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const calendarDay = `[parseDashboardDate('2026-10-01')].map(d => [d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-'))[0]`
|
|
19
|
+
|
|
20
|
+
describe('parseDashboardDate', () => {
|
|
21
|
+
for (const zone of ['America/Los_Angeles', 'UTC', 'Asia/Manila', 'Pacific/Kiritimati']) {
|
|
22
|
+
it(`reads a calendar date as that day in ${zone}`, async () => {
|
|
23
|
+
expect(await inZone(zone, calendarDay)).toBe('2026-10-1')
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
it('reads an offsetless database timestamp as UTC, wherever it runs', async () => {
|
|
28
|
+
for (const zone of ['America/Los_Angeles', 'Asia/Manila'])
|
|
29
|
+
expect(await inZone(zone, `parseDashboardDate('2026-10-01 14:30:00').toISOString()`)).toBe('2026-10-01T14:30:00.000Z')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('leaves an ISO string with an offset, and a Date, as they are', async () => {
|
|
33
|
+
expect(await inZone('America/Los_Angeles', `parseDashboardDate('2026-10-01T14:30:00+08:00').toISOString()`)).toBe('2026-10-01T06:30:00.000Z')
|
|
34
|
+
const at = new Date('2026-10-01T00:00:00Z')
|
|
35
|
+
const { parseDashboardDate } = await import('./dashboard-dates')
|
|
36
|
+
expect(parseDashboardDate(at)).toBe(at)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('the reading it replaces is the bug: a calendar date lands on the day before west of UTC', async () => {
|
|
40
|
+
// The control. Without it, every assertion above would pass in a zone
|
|
41
|
+
// where the two readings agree.
|
|
42
|
+
expect(await inZone('America/Los_Angeles', `[new Date('2026-10-01')].map(d => d.getDate())[0]`)).toBe('30')
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a date value from a dashboard row.
|
|
3
|
+
*
|
|
4
|
+
* A calendar date (`2026-10-01`) is a day, not an instant, so it is read as
|
|
5
|
+
* local midnight. `new Date('2026-10-01')` reads it as UTC midnight instead,
|
|
6
|
+
* which every zone west of UTC renders as the day before: a coupon starting
|
|
7
|
+
* on October 1st showed September 30th in Los Angeles.
|
|
8
|
+
*
|
|
9
|
+
* A database timestamp written without an offset (`2026-10-01 14:30:00`) is
|
|
10
|
+
* UTC, which is how the framework writes it, so it gains the `Z` it lacks.
|
|
11
|
+
* Anything else, ISO strings with an offset among them, is left to `Date`.
|
|
12
|
+
*/
|
|
13
|
+
export function parseDashboardDate(value: unknown): Date {
|
|
14
|
+
if (value instanceof Date)
|
|
15
|
+
return value
|
|
16
|
+
const text = String(value)
|
|
17
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(text))
|
|
18
|
+
return new Date(`${text}T00:00:00`)
|
|
19
|
+
if (/^\d{4}-\d{2}-\d{2} \d/.test(text))
|
|
20
|
+
return new Date(`${text.replace(' ', 'T')}Z`)
|
|
21
|
+
return new Date(text)
|
|
22
|
+
}
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.268",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
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.268",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@iconify-json/f7": "^1.2.2",
|
|
47
47
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
48
|
-
"@stacksjs/mobile": "0.75.
|
|
49
|
-
"@stacksjs/sanitizer": "0.2.
|
|
50
|
-
"@stacksjs/stx": "0.2.
|
|
48
|
+
"@stacksjs/mobile": "0.75.268",
|
|
49
|
+
"@stacksjs/sanitizer": "0.2.667",
|
|
50
|
+
"@stacksjs/stx": "0.2.667",
|
|
51
51
|
"@xterm/addon-fit": "^0.11.0",
|
|
52
52
|
"@xterm/xterm": "^6.0.0",
|
|
53
53
|
"ts-qr-codes": "^0.1.8"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import { formatCurrency } from '@stacksjs/commerce/money'
|
|
3
|
+
import { parseDashboardDate } from '../../../../functions/dashboard-dates'
|
|
3
4
|
/**
|
|
4
5
|
* The data table.
|
|
5
6
|
*
|
|
@@ -276,14 +277,14 @@ function displayValue(row: DashboardTableRow, column: DashboardTableColumn): str
|
|
|
276
277
|
return Number.isFinite(amount) ? amount.toLocaleString() : String(value)
|
|
277
278
|
}
|
|
278
279
|
if (column.type === 'date') {
|
|
279
|
-
const at =
|
|
280
|
+
const at = parseDashboardDate(value)
|
|
280
281
|
return Number.isNaN(at.getTime()) ? String(value) : at.toLocaleDateString()
|
|
281
282
|
}
|
|
282
283
|
// An event or log row is ordered by when it happened, and to the minute, so
|
|
283
284
|
// the date alone is not enough to read it. Separate from `date` rather than
|
|
284
285
|
// a flag on it because the two render differently everywhere they appear.
|
|
285
286
|
if (column.type === 'datetime') {
|
|
286
|
-
const at =
|
|
287
|
+
const at = parseDashboardDate(value)
|
|
287
288
|
return Number.isNaN(at.getTime())
|
|
288
289
|
? String(value)
|
|
289
290
|
: at.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' })
|
|
@@ -346,20 +347,6 @@ function hasBadge(row: DashboardTableRow, column: DashboardTableColumn): boolean
|
|
|
346
347
|
return badgeLabel(row, column) !== ''
|
|
347
348
|
}
|
|
348
349
|
|
|
349
|
-
/**
|
|
350
|
-
* Parse a stored timestamp.
|
|
351
|
-
*
|
|
352
|
-
* SQLite hands back `2026-01-01 12:00:00`, with a space and no zone. `new
|
|
353
|
-
* Date()` reads that as local time where it reads it at all, so every row
|
|
354
|
-
* shifted by the viewer's offset - a date near midnight landing on the wrong
|
|
355
|
-
* day. The hand-rolled tables each normalised it themselves; this is the same
|
|
356
|
-
* knowledge in the one place that needs it.
|
|
357
|
-
*/
|
|
358
|
-
function toDate(value: unknown): Date {
|
|
359
|
-
const text = String(value)
|
|
360
|
-
return new Date(/^\d{4}-\d{2}-\d{2} \d/.test(text) ? `${text.replace(' ', 'T')}Z` : text)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
350
|
/** The pill's text: the mapped label, else the value with its underscores read as spaces. */
|
|
364
351
|
function badgeLabel(row: DashboardTableRow, column: DashboardTableColumn): string {
|
|
365
352
|
const value = rawValue(row, column.key)
|
|
@@ -397,7 +384,7 @@ function compare(a: any, b: any, type: DashboardTableColumn['type']): number {
|
|
|
397
384
|
// comparison below, which is only accidentally right for ISO timestamps and
|
|
398
385
|
// wrong for every other format.
|
|
399
386
|
if (type === 'date' || type === 'datetime')
|
|
400
|
-
return
|
|
387
|
+
return parseDashboardDate(a).getTime() - parseDashboardDate(b).getTime()
|
|
401
388
|
if (type === 'boolean')
|
|
402
389
|
return (a ? 1 : 0) - (b ? 1 : 0)
|
|
403
390
|
|