@stacksjs/notifications 0.70.23 → 0.70.26
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/dist/index.js +1 -1
- package/dist/src/drivers/database.d.ts +40 -0
- package/dist/src/index.d.ts +87 -0
- package/dist/src/preferences.d.ts +106 -0
- package/package.json +20 -12
- package/dist/chat.d.ts +0 -1
- package/dist/config.d.ts +0 -3
- package/dist/email.d.ts +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/push.d.ts +0 -1
- package/dist/sms.d.ts +0 -1
- package/dist/tailwind.config.d.ts +0 -34
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import
|
|
2
|
+
import{log as Y}from"@stacksjs/cli";import{notification as A}from"@stacksjs/config";import{mail as M}from"@stacksjs/email";import*as $ from"@stacksjs/chat";import{log as C}from"@stacksjs/cli";import{db as R}from"@stacksjs/database";var U={async send(x){let z=new Date().toISOString(),F=await R.insertInto("notifications").values({user_id:x.userId,type:x.type,data:JSON.stringify(x.data),read_at:null,created_at:z,updated_at:z}).execute(),K=Number(F?.[0]?.insertId??F?.insertId??F?.lastInsertRowid??F?.lastInsertId??0);return C.info(`Database notification sent to user ${x.userId}: ${x.type}`),{id:K,user_id:x.userId,type:x.type,data:JSON.stringify(x.data),read_at:null,created_at:z,updated_at:z}},async getUserNotifications(x){return await R.selectFrom("notifications").selectAll().where("user_id","=",x).orderBy("created_at","desc").execute()},async getUnreadNotifications(x){return await R.selectFrom("notifications").selectAll().where("user_id","=",x).where("read_at","is",null).orderBy("created_at","desc").execute()},async markAsRead(x){await R.updateTable("notifications").set({read_at:new Date().toISOString()}).where("id","=",x).execute()},async markAllAsRead(x){await R.updateTable("notifications").set({read_at:new Date().toISOString()}).where("user_id","=",x).where("read_at","is",null).execute()},async unreadCount(x){let z=await R.selectFrom("notifications").select(R.fn.countAll().as("count")).where("user_id","=",x).where("read_at","is",null).executeTakeFirst();return Number(z?.count??0)},async deleteNotification(x){await R.deleteFrom("notifications").where("id","=",x).execute()},async deleteAllNotifications(x){await R.deleteFrom("notifications").where("user_id","=",x).execute()}};import*as g from"@stacksjs/email";import*as v from"@stacksjs/push";import*as H from"@stacksjs/sms";import{log as E}from"@stacksjs/cli";import{db as _}from"@stacksjs/database";var V="notification_preferences";async function W(x,z){let G=new Map;try{let F=_.selectFrom(V).select(["channel","enabled","category"]).where("user_id","=",x);if(z!==void 0)F=F.where("category","=",z);let K=await F.execute();for(let Q of K)G.set(Q.channel,Q.enabled===!0||Q.enabled===1)}catch(F){E.debug?.(`[notifications] preferences lookup failed (table missing?): ${F.message}`)}return G}async function q(x,z,G,F){let K=new Date().toISOString(),Q=F??null,J=_,O=await J.selectFrom(V).select(["id"]).where("user_id","=",x).where("channel","=",z).where("category",Q===null?"is":"=",Q).executeTakeFirst();if(O?.id){await J.updateTable(V).set({enabled:G,updated_at:K}).where("id","=",O.id).execute();return}await J.insertInto(V).values({user_id:x,channel:z,enabled:G,category:Q,created_at:K,updated_at:K}).execute()}async function j(x,z){for(let G of z)await q(x,G.channel,G.enabled,G.category)}async function X(x,z,G){let F=await W(x,G);if(G!==void 0){let K=await W(x,void 0);for(let[Q,J]of K)if(!F.has(Q))F.set(Q,J)}return z.filter((K)=>{let Q=F.get(K);return Q===void 0?!0:Q===!0})}var D=A;function L(x){return $[x||"slack"]}function T(x){if(x)try{return M.use(x)}catch(z){Y.warn(`[notifications] email driver '${x}' not registered \u2014 falling back to default mail singleton (${z.message})`)}return M}function m(x){return H[x||"twilio"]}function N(){return U}function S(x,z){let G=x||D?.default||"email",F=z;switch(G){case"email":return T(F);case"chat":return L(F);case"sms":return m(F);case"database":return N();default:throw Error(`Notification type "${G}" is not supported`)}}async function Gx(x,z,G=["email"],F={}){let K=G;if(x.userId&&!F.ignorePreferences)try{K=await X(x.userId,G,F.category)}catch(J){Y.warn(`[notify] preferences filter failed, sending all channels: ${J.message}`)}return(await Promise.allSettled(K.map(async(J)=>{switch(J){case"email":{if(!x.email)throw Error("[notify] email channel requires recipient.email");await T().send({to:x.email,subject:z.subject,text:z.body,html:`<p>${P(z.body)}</p>`});break}case"sms":{let O=m();if(O&&typeof O==="object"&&"send"in O){if(!x.phone)throw Error("[notify] sms channel requires recipient.phone");await O.send({to:x.phone,body:z.body})}break}case"chat":{let O=L();if(O&&typeof O==="object"&&"send"in O)await O.send({body:z.body});break}case"database":{if(!x.userId)throw Error("[notify] database channel requires recipient.userId");await U.send({userId:x.userId,type:z.subject||"notification",data:{body:z.body,...z.data}});break}case"push":throw Error("[notify] push channel is filtered by preferences but not yet wired into a default driver");default:throw Error(`Unsupported notification channel: ${J}`)}}))).map((J,O)=>{let Z=K[O];if(J.status==="rejected"){let B=J.reason instanceof Error?J.reason.message:String(J.reason);Y.warn(`[notify] ${Z} channel failed: ${B}`)}return{channel:Z,success:J.status==="fulfilled",error:J.status==="rejected"?J.reason:void 0}})}function Jx(){return S()}function P(x){return String(x??"").replace(/[&<>"']/g,(z)=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[z])}export{m as useSMS,S as useNotification,T as useEmail,N as useDatabase,L as useChat,q as setNotificationPreference,Gx as notify,Jx as notification,W as getNotificationPreferences,X as filterChannelsByPreferences,j as bulkSetPreferences,U as DatabaseNotificationDriver};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare function useDatabase(): typeof DatabaseNotificationDriver;
|
|
2
|
+
/**
|
|
3
|
+
* @defaultValue
|
|
4
|
+
* ```ts
|
|
5
|
+
* {
|
|
6
|
+
* send: () => unknown,
|
|
7
|
+
* getUserNotifications: () => unknown,
|
|
8
|
+
* getUnreadNotifications: () => unknown,
|
|
9
|
+
* markAsRead: () => unknown,
|
|
10
|
+
* markAllAsRead: () => unknown,
|
|
11
|
+
* unreadCount: () => unknown,
|
|
12
|
+
* deleteNotification: () => unknown,
|
|
13
|
+
* deleteAllNotifications: () => unknown
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const DatabaseNotificationDriver: {
|
|
18
|
+
send: (options: CreateNotificationOptions) => Promise<DatabaseNotification>;
|
|
19
|
+
getUserNotifications: (userId: number) => Promise<DatabaseNotification[]>;
|
|
20
|
+
getUnreadNotifications: (userId: number) => Promise<DatabaseNotification[]>;
|
|
21
|
+
markAsRead: (id: number) => Promise<void>;
|
|
22
|
+
markAllAsRead: (userId: number) => Promise<void>;
|
|
23
|
+
unreadCount: (userId: number) => Promise<number>;
|
|
24
|
+
deleteNotification: (id: number) => Promise<void>;
|
|
25
|
+
deleteAllNotifications: (userId: number) => Promise<void>
|
|
26
|
+
};
|
|
27
|
+
export declare interface DatabaseNotification {
|
|
28
|
+
id: number
|
|
29
|
+
user_id: number
|
|
30
|
+
type: string
|
|
31
|
+
data: string
|
|
32
|
+
read_at: string | null
|
|
33
|
+
created_at: string
|
|
34
|
+
updated_at: string | null
|
|
35
|
+
}
|
|
36
|
+
export declare interface CreateNotificationOptions {
|
|
37
|
+
userId: number
|
|
38
|
+
type: string
|
|
39
|
+
data: Record<string, any>
|
|
40
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { chat, email, sms } from './drivers';
|
|
2
|
+
import { DatabaseNotificationDriver } from './drivers/database';
|
|
3
|
+
import { filterChannelsByPreferences } from './preferences';
|
|
4
|
+
import type { EmailMessage, EmailResult } from '@stacksjs/types';
|
|
5
|
+
export type { CreateNotificationOptions, DatabaseNotification } from './drivers/database';
|
|
6
|
+
export type { NotificationPreferenceRow, PreferenceChannel } from './preferences';
|
|
7
|
+
export declare function useChat(driver?: string): typeof chat[keyof typeof chat];
|
|
8
|
+
/**
|
|
9
|
+
* Return the email transport — by default the @stacksjs/email Mail
|
|
10
|
+
* singleton, which lazy-resolves its driver from `config.email.default`
|
|
11
|
+
* (so `MAIL_MAILER=log` in dev / `ses` in prod just works). Pass an
|
|
12
|
+
* explicit driver name to scope to a specific transport — useful in
|
|
13
|
+
* tests that want to assert against `LogEmailDriver` specifically without
|
|
14
|
+
* touching the global config.
|
|
15
|
+
*
|
|
16
|
+
* Earlier this function returned the *driver namespace* (e.g.
|
|
17
|
+
* `{ SESDriver, default }`), which has no `send`. The `'send' in driver`
|
|
18
|
+
* guard in `notify()` was always false, so the email channel silently
|
|
19
|
+
* no-op'd for every booking confirmation, host alert, etc.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useEmail(driver?: string): EmailTransport;
|
|
22
|
+
export declare function useSMS(driver?: string): typeof sms[keyof typeof sms];
|
|
23
|
+
export declare function useDatabase(): typeof DatabaseNotificationDriver;
|
|
24
|
+
export declare function useNotification(typeParam?: string, driverParam?: string): typeof chat[keyof typeof chat] | typeof email[keyof typeof email] | typeof sms[keyof typeof sms] | typeof DatabaseNotificationDriver;
|
|
25
|
+
/**
|
|
26
|
+
* Send a notification through multiple channels simultaneously.
|
|
27
|
+
* Uses Promise.allSettled so one channel failure doesn't block others.
|
|
28
|
+
*
|
|
29
|
+
* When `recipient.userId` is set and `options.ignorePreferences` is not
|
|
30
|
+
* `true`, the channel list is first filtered through the user's
|
|
31
|
+
* `notification_preferences` rows — any channel they've explicitly
|
|
32
|
+
* disabled is silently skipped. Channels with no preference recorded fall
|
|
33
|
+
* through as enabled (default-allow), so introducing this feature doesn't
|
|
34
|
+
* regress notifications for users who haven't visited the preferences UI.
|
|
35
|
+
*
|
|
36
|
+
* For transactional notifications that must always go out (password
|
|
37
|
+
* resets, security alerts, billing failures), pass
|
|
38
|
+
* `{ ignorePreferences: true }`.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* // respects user preferences
|
|
43
|
+
* await notify({ userId: 7, email: 'a@x' }, { body: 'New message' }, ['email', 'sms'])
|
|
44
|
+
*
|
|
45
|
+
* // bypasses preferences (security alert)
|
|
46
|
+
* await notify({ userId: 7, email: 'a@x' }, { body: 'New login' }, ['email'], { ignorePreferences: true })
|
|
47
|
+
*
|
|
48
|
+
* // category-specific opt-out
|
|
49
|
+
* await notify({ userId: 7, email: 'a@x' }, { body: 'Sale!' }, ['email'], { category: 'marketing' })
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function notify(recipient: NotificationRecipient, payload: NotificationPayload, channels?: NotificationChannel[], options?: NotifyOptions): Promise<NotifyResult[]>;
|
|
53
|
+
export declare function notification(): ReturnType<typeof useNotification>;
|
|
54
|
+
/** Optional flags accepted by {@link notify}. */
|
|
55
|
+
export declare interface NotifyOptions {
|
|
56
|
+
ignorePreferences?: boolean
|
|
57
|
+
category?: string
|
|
58
|
+
}
|
|
59
|
+
/** Minimal transport contract used by `notify()` — anything that exposes a
|
|
60
|
+
* `send(EmailMessage)` returning an `EmailResult` works (the @stacksjs/email
|
|
61
|
+
* Mail singleton, a per-test LogEmailDriver, a custom mock, etc.). */
|
|
62
|
+
export declare interface EmailTransport {
|
|
63
|
+
send: (message: EmailMessage) => Promise<EmailResult>
|
|
64
|
+
}
|
|
65
|
+
export declare interface NotificationPayload {
|
|
66
|
+
subject?: string
|
|
67
|
+
body: string
|
|
68
|
+
data?: Record<string, unknown>
|
|
69
|
+
}
|
|
70
|
+
export declare interface NotificationRecipient {
|
|
71
|
+
email?: string
|
|
72
|
+
phone?: string
|
|
73
|
+
userId?: number
|
|
74
|
+
}
|
|
75
|
+
export declare interface NotifyResult {
|
|
76
|
+
channel: NotificationChannel
|
|
77
|
+
success: boolean
|
|
78
|
+
error?: Error
|
|
79
|
+
}
|
|
80
|
+
export type NotificationChannel = 'email' | 'sms' | 'chat' | 'database' | 'push';
|
|
81
|
+
export { DatabaseNotificationDriver } from './drivers/database';
|
|
82
|
+
export {
|
|
83
|
+
bulkSetPreferences,
|
|
84
|
+
filterChannelsByPreferences,
|
|
85
|
+
getNotificationPreferences,
|
|
86
|
+
setNotificationPreference,
|
|
87
|
+
} from './preferences';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { NotificationChannel } from './index';
|
|
2
|
+
/**
|
|
3
|
+
* Load all notification preferences for a user as a Map keyed by channel.
|
|
4
|
+
* Returns `Map<channel, enabled>` — channels with no row recorded are
|
|
5
|
+
* absent from the Map (callers should treat absent = enabled by default).
|
|
6
|
+
*
|
|
7
|
+
* If the `notification_preferences` table doesn't exist yet (apps that
|
|
8
|
+
* haven't applied the migration) this returns an empty Map and logs a
|
|
9
|
+
* one-line debug message rather than throwing — the user-facing notify()
|
|
10
|
+
* flow shouldn't 500 because of an opt-in feature.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const prefs = await getNotificationPreferences(user.id)
|
|
15
|
+
* if (prefs.get('email') === false) console.log('user opted out of email')
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function getNotificationPreferences(userId: number, category?: string): Promise<Map<PreferenceChannel, boolean>>;
|
|
19
|
+
/**
|
|
20
|
+
* Upsert a single preference row for `(user_id, channel, category)`.
|
|
21
|
+
* The combination is treated as the natural key — calling this twice with
|
|
22
|
+
* the same triple just toggles `enabled` on the existing row.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* // user opts out of marketing emails
|
|
27
|
+
* await setNotificationPreference(user.id, 'email', false, 'marketing')
|
|
28
|
+
* // ...later, opts back in
|
|
29
|
+
* await setNotificationPreference(user.id, 'email', true, 'marketing')
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function setNotificationPreference(userId: number, channel: PreferenceChannel, enabled: boolean, category?: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Bulk upsert preferences for a user — convenient for "save preferences"
|
|
35
|
+
* forms that submit the user's full opt-in/out matrix in one POST.
|
|
36
|
+
*
|
|
37
|
+
* Iterates one upsert per entry rather than one mega-query because the
|
|
38
|
+
* underlying conflict logic is keyed on `(user_id, channel, category)`
|
|
39
|
+
* and a single SQL statement can't express that across N rows portably.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* await bulkSetPreferences(user.id, [
|
|
44
|
+
* { channel: 'email', enabled: false, category: 'marketing' },
|
|
45
|
+
* { channel: 'sms', enabled: true },
|
|
46
|
+
* { channel: 'push', enabled: false },
|
|
47
|
+
* ])
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function bulkSetPreferences(userId: number, prefs: Array<{ channel: PreferenceChannel, enabled: boolean, category?: string }>): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Filter a list of channels through a user's preferences.
|
|
53
|
+
*
|
|
54
|
+
* Returns the subset the user is opted *in* for. Channels with no row
|
|
55
|
+
* recorded fall through as enabled (default-allow) so that introducing
|
|
56
|
+
* the preferences feature doesn't suddenly break notifications for users
|
|
57
|
+
* who never visited the preferences page.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const allowed = await filterChannelsByPreferences(user.id, ['email', 'sms', 'push'])
|
|
62
|
+
* // -> ['email', 'push'] (user disabled sms)
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function filterChannelsByPreferences<T extends PreferenceChannel>(userId: number, channels: T[], category?: string): Promise<T[]>;
|
|
66
|
+
/**
|
|
67
|
+
* `notification_preferences` table — user-level opt-out per channel
|
|
68
|
+
* (and optionally per category, e.g. `marketing` vs `system`).
|
|
69
|
+
*
|
|
70
|
+
* The migration is intentionally NOT shipped here — apps maintain their
|
|
71
|
+
* own migration directory and column conventions. Generate the migration
|
|
72
|
+
* yourself; the schema below is what the runtime expects.
|
|
73
|
+
*
|
|
74
|
+
* ```sql
|
|
75
|
+
* CREATE TABLE notification_preferences (
|
|
76
|
+
* id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
77
|
+
* user_id INTEGER NOT NULL,
|
|
78
|
+
* channel TEXT NOT NULL, -- email | sms | chat | database | push
|
|
79
|
+
* enabled INTEGER NOT NULL DEFAULT 1, -- boolean (0/1)
|
|
80
|
+
* category TEXT, -- optional, e.g. 'marketing'
|
|
81
|
+
* created_at TEXT NOT NULL,
|
|
82
|
+
* updated_at TEXT NOT NULL,
|
|
83
|
+
* UNIQUE (user_id, channel, category)
|
|
84
|
+
* );
|
|
85
|
+
*
|
|
86
|
+
* CREATE INDEX idx_notification_preferences_user
|
|
87
|
+
* ON notification_preferences (user_id);
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* Postgres / MySQL equivalents: use `BOOLEAN` for `enabled`, `BIGINT` for
|
|
91
|
+
* IDs, and `TIMESTAMP` for the timestamp columns. The `UNIQUE (user_id,
|
|
92
|
+
* channel, category)` constraint is what makes the upsert below safe; if
|
|
93
|
+
* your DB doesn't allow `NULL` to participate in `UNIQUE`, treat
|
|
94
|
+
* `category IS NULL` as a sentinel "global" category instead.
|
|
95
|
+
*/
|
|
96
|
+
export declare interface NotificationPreferenceRow {
|
|
97
|
+
id: number
|
|
98
|
+
user_id: number
|
|
99
|
+
channel: NotificationChannel | 'push'
|
|
100
|
+
enabled: boolean | 0 | 1
|
|
101
|
+
category?: string | null
|
|
102
|
+
created_at: string
|
|
103
|
+
updated_at: string
|
|
104
|
+
}
|
|
105
|
+
/** All channels that can be filtered through preferences. */
|
|
106
|
+
export type PreferenceChannel = NotificationChannel | 'push';
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/notifications",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.70.
|
|
4
|
+
"version": "0.70.26",
|
|
5
5
|
"description": "The Stacks notifications integration.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
|
-
"contributors": [
|
|
7
|
+
"contributors": [
|
|
8
|
+
"Chris Breuer <chris@stacksjs.com>"
|
|
9
|
+
],
|
|
8
10
|
"license": "MIT",
|
|
9
11
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
|
10
12
|
"homepage": "https://github.com/stacksjs/stacks/tree/main/storage/framework/core/notifications#readme",
|
|
@@ -31,29 +33,35 @@
|
|
|
31
33
|
],
|
|
32
34
|
"exports": {
|
|
33
35
|
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"bun": "./src/index.ts",
|
|
34
38
|
"import": "./dist/index.js"
|
|
35
39
|
},
|
|
36
40
|
"./*": {
|
|
41
|
+
"bun": "./src/*",
|
|
37
42
|
"import": "./dist/*"
|
|
38
43
|
}
|
|
39
44
|
},
|
|
40
45
|
"module": "dist/index.js",
|
|
41
46
|
"types": "dist/index.d.ts",
|
|
42
|
-
"files": [
|
|
47
|
+
"files": [
|
|
48
|
+
"README.md",
|
|
49
|
+
"dist"
|
|
50
|
+
],
|
|
43
51
|
"scripts": {
|
|
44
52
|
"build": "bun build.ts",
|
|
45
53
|
"typecheck": "bun tsc --noEmit",
|
|
46
54
|
"prepublishOnly": "bun run build"
|
|
47
55
|
},
|
|
48
56
|
"devDependencies": {
|
|
49
|
-
"@stacksjs/chat": "0.70.
|
|
50
|
-
"@stacksjs/cli": "0.70.
|
|
51
|
-
"@stacksjs/config": "0.70.
|
|
52
|
-
"
|
|
53
|
-
"@stacksjs/email": "0.70.
|
|
54
|
-
"@stacksjs/error-handling": "0.70.
|
|
55
|
-
"@stacksjs/push": "0.70.
|
|
56
|
-
"@stacksjs/sms": "0.70.
|
|
57
|
-
"@stacksjs/types": "0.70.
|
|
57
|
+
"@stacksjs/chat": "0.70.23",
|
|
58
|
+
"@stacksjs/cli": "0.70.23",
|
|
59
|
+
"@stacksjs/config": "0.70.23",
|
|
60
|
+
"better-dx": "^0.2.12",
|
|
61
|
+
"@stacksjs/email": "0.70.23",
|
|
62
|
+
"@stacksjs/error-handling": "0.70.23",
|
|
63
|
+
"@stacksjs/push": "0.70.23",
|
|
64
|
+
"@stacksjs/sms": "0.70.23",
|
|
65
|
+
"@stacksjs/types": "0.70.23"
|
|
58
66
|
}
|
|
59
67
|
}
|
package/dist/chat.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * as chat from '@stacksjs/chat'
|
package/dist/config.d.ts
DELETED
package/dist/email.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * as email from '@stacksjs/email'
|
package/dist/index.d.ts
DELETED
package/dist/push.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * as push from '@stacksjs/push'
|
package/dist/sms.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * as sms from '@stacksjs/sms'
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
theme: {
|
|
3
|
-
screens: {
|
|
4
|
-
sm: '480px',
|
|
5
|
-
md: '768px',
|
|
6
|
-
lg: '976px',
|
|
7
|
-
xl: '1440px',
|
|
8
|
-
},
|
|
9
|
-
colors: {
|
|
10
|
-
'blue': '#1fb6ff',
|
|
11
|
-
'purple': '#7e5bef',
|
|
12
|
-
'pink': '#ff49db',
|
|
13
|
-
'orange': '#ff7849',
|
|
14
|
-
'green': '#13ce66',
|
|
15
|
-
'yellow': '#ffc82c',
|
|
16
|
-
'gray-dark': '#273444',
|
|
17
|
-
'gray': '#8492a6',
|
|
18
|
-
'gray-light': '#d3dce6',
|
|
19
|
-
},
|
|
20
|
-
fontFamily: {
|
|
21
|
-
sans: ['Graphik', 'sans-serif'],
|
|
22
|
-
serif: ['Merriweather', 'serif'],
|
|
23
|
-
},
|
|
24
|
-
extend: {
|
|
25
|
-
spacing: {
|
|
26
|
-
128: '32rem',
|
|
27
|
-
144: '36rem',
|
|
28
|
-
},
|
|
29
|
-
borderRadius: {
|
|
30
|
-
'4xl': '2rem',
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
};
|