@strav/cache 1.0.0-alpha.29 → 1.0.0-alpha.30
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strav/cache",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.30",
|
|
4
4
|
"description": "Strav cache layer — Cache abstraction + MemoryCache (in-process) + PostgresCache (cross-process ledger) + RedisCache (Bun.RedisClient, all data structures incl. tagged sets) + MemcachedCache (text-protocol client over Bun.connect). Atomic increments, distributed locks, tagged invalidation. Mirrors @strav/broadcast: kernel-free core in the root, every driver under its own subpath.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"./memory": "./src/drivers/memory/index.ts",
|
|
11
11
|
"./postgres": "./src/drivers/postgres/index.ts",
|
|
12
12
|
"./redis": "./src/drivers/redis/index.ts",
|
|
13
|
-
"./memcached": "./src/drivers/memcached/index.ts"
|
|
13
|
+
"./memcached": "./src/drivers/memcached/index.ts",
|
|
14
|
+
"./console": "./src/console/index.ts"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
17
|
"src",
|
|
@@ -23,10 +24,11 @@
|
|
|
23
24
|
"access": "public"
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"@strav/
|
|
27
|
+
"@strav/cli": "1.0.0-alpha.30",
|
|
28
|
+
"@strav/kernel": "1.0.0-alpha.30"
|
|
27
29
|
},
|
|
28
30
|
"peerDependencies": {
|
|
29
|
-
"@strav/database": "1.0.0-alpha.
|
|
31
|
+
"@strav/database": "1.0.0-alpha.30",
|
|
30
32
|
"@types/bun": ">=1.3.14"
|
|
31
33
|
},
|
|
32
34
|
"peerDependenciesMeta": {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bun strav cache:clear [--force]` — flush every key from the
|
|
3
|
+
* active cache store.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors `Cache.flush()` directly. Confirms before running unless
|
|
6
|
+
* `--force` is set (CI / scripted teardown). Driver-specific
|
|
7
|
+
* notes:
|
|
8
|
+
*
|
|
9
|
+
* - `MemoryCache` — clears the in-process map; only affects this
|
|
10
|
+
* process.
|
|
11
|
+
* - `RedisCache` — `SCAN` + `DEL` under the configured `prefix`
|
|
12
|
+
* so other apps sharing the Redis DB are untouched.
|
|
13
|
+
* - `PostgresCache` — `TRUNCATE` of the cache ledger table.
|
|
14
|
+
* - `MemcachedCache` — `FLUSH_ALL` (server-wide).
|
|
15
|
+
*
|
|
16
|
+
* Use scoped invalidation (`cache.tags(...).flush()`,
|
|
17
|
+
* `cache.forget(key)`) in production code paths; `cache:clear` is
|
|
18
|
+
* the deploy-time / dev tool.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { Command, type ExecuteArgs, ExitCode } from '@strav/cli'
|
|
22
|
+
import { Cache } from '../cache.ts'
|
|
23
|
+
|
|
24
|
+
export class CacheClear extends Command {
|
|
25
|
+
static signature = 'cache:clear {--force}'
|
|
26
|
+
static description = 'Flush every entry from the active cache store.'
|
|
27
|
+
static providers = ['config', 'logger', 'cache']
|
|
28
|
+
|
|
29
|
+
override async execute({ flags }: ExecuteArgs): Promise<number> {
|
|
30
|
+
if (flags.force !== true) {
|
|
31
|
+
const ok = await this.confirm(
|
|
32
|
+
'Flush every entry from the active cache store? This is irreversible.',
|
|
33
|
+
)
|
|
34
|
+
if (!ok) {
|
|
35
|
+
this.info('Aborted.')
|
|
36
|
+
return ExitCode.Success
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const cache = this.app.resolve(Cache)
|
|
40
|
+
await cache.flush()
|
|
41
|
+
this.success('Cache flushed.')
|
|
42
|
+
return ExitCode.Success
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `CacheConsoleProvider` — declares the `cache:*` commands.
|
|
3
|
+
*
|
|
4
|
+
* Apps add it to `bootstrap/providers.ts` alongside the cache
|
|
5
|
+
* provider (`CacheProvider` for in-memory, `RedisCacheProvider`,
|
|
6
|
+
* `PostgresCacheProvider`, or `MemcachedCacheProvider`). Separate
|
|
7
|
+
* provider so apps that don't ship a CLI don't pay the cost of
|
|
8
|
+
* resolving commands at boot — same pattern as
|
|
9
|
+
* `QueueConsoleProvider` and `RagConsoleProvider`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { ConsoleProvider } from '@strav/cli'
|
|
13
|
+
import { CacheClear } from './cache_clear.ts'
|
|
14
|
+
import { CacheForget } from './cache_forget.ts'
|
|
15
|
+
import { CacheList } from './cache_list.ts'
|
|
16
|
+
|
|
17
|
+
export class CacheConsoleProvider extends ConsoleProvider {
|
|
18
|
+
override readonly name = 'console.cache'
|
|
19
|
+
override readonly commands = [CacheClear, CacheForget, CacheList] as const
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bun strav cache:forget <key>` — drop one cache entry.
|
|
3
|
+
*
|
|
4
|
+
* Exit code 0 when a key was removed; 0 with a warning when nothing
|
|
5
|
+
* matched (no key to forget is not an error — apps script this from
|
|
6
|
+
* deploy hooks where the entry may or may not be live).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Command, type ExecuteArgs, ExitCode } from '@strav/cli'
|
|
10
|
+
import { Cache } from '../cache.ts'
|
|
11
|
+
|
|
12
|
+
export class CacheForget extends Command {
|
|
13
|
+
static signature = 'cache:forget {key}'
|
|
14
|
+
static description = 'Delete a single cache entry by key.'
|
|
15
|
+
static providers = ['config', 'logger', 'cache']
|
|
16
|
+
|
|
17
|
+
override async execute({ args }: ExecuteArgs): Promise<number> {
|
|
18
|
+
const key = args.key as string
|
|
19
|
+
const cache = this.app.resolve(Cache)
|
|
20
|
+
const removed = await cache.forget(key)
|
|
21
|
+
if (removed) {
|
|
22
|
+
this.success(`Forgot "${key}".`)
|
|
23
|
+
} else {
|
|
24
|
+
this.warn(`No entry for "${key}".`)
|
|
25
|
+
}
|
|
26
|
+
return ExitCode.Success
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bun strav cache:list` — print the active cache driver + key
|
|
3
|
+
* config knobs.
|
|
4
|
+
*
|
|
5
|
+
* Diagnostic only. Useful for verifying that `config/cache.ts`
|
|
6
|
+
* parses cleanly and that the deployed binary picked up the
|
|
7
|
+
* intended driver (Redis vs in-memory in CI, etc.). No mutations.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Command, type ExecuteArgs, ExitCode } from '@strav/cli'
|
|
11
|
+
import { ConfigRepository } from '@strav/kernel'
|
|
12
|
+
|
|
13
|
+
export class CacheList extends Command {
|
|
14
|
+
static signature = 'cache:list'
|
|
15
|
+
static description = 'Show the active cache driver and its configuration.'
|
|
16
|
+
static providers = ['config', 'logger', 'cache']
|
|
17
|
+
|
|
18
|
+
override async execute(_args: ExecuteArgs): Promise<number> {
|
|
19
|
+
const cfg = this.app.resolve(ConfigRepository).get('cache') as
|
|
20
|
+
| (Record<string, unknown> & { driver?: string })
|
|
21
|
+
| undefined
|
|
22
|
+
|
|
23
|
+
if (cfg === undefined) {
|
|
24
|
+
this.info('No `config.cache` entry. The cache provider booted with defaults.')
|
|
25
|
+
return ExitCode.Success
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const driver = cfg.driver ?? '(unset)'
|
|
29
|
+
this.info(`Driver: ${driver}`)
|
|
30
|
+
for (const [key, value] of Object.entries(cfg)) {
|
|
31
|
+
if (key === 'driver') continue
|
|
32
|
+
const printed =
|
|
33
|
+
typeof value === 'string' && key.toLowerCase().includes('password')
|
|
34
|
+
? '***'
|
|
35
|
+
: typeof value === 'object'
|
|
36
|
+
? JSON.stringify(value)
|
|
37
|
+
: String(value)
|
|
38
|
+
this.info(` ${key}: ${printed}`)
|
|
39
|
+
}
|
|
40
|
+
return ExitCode.Success
|
|
41
|
+
}
|
|
42
|
+
}
|