@owlmeans/bot-postgres 0.0.0-stage → 0.1.18-rc.2
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 +143 -2
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/bot-postgres/SKILL.md +181 -0
- package/build/helper.d.ts +9 -0
- package/build/helper.d.ts.map +1 -0
- package/build/helper.js +27 -0
- package/build/helper.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +3 -0
- package/build/index.js.map +1 -0
- package/build/resource.d.ts +23 -0
- package/build/resource.d.ts.map +1 -0
- package/build/resource.js +75 -0
- package/build/resource.js.map +1 -0
- package/build/types.d.ts +26 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/types.local.d.ts +4 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/package.json +52 -4
- package/src/helper.ts +33 -0
- package/src/index.ts +3 -0
- package/src/resource.ts +100 -0
- package/src/types.local.ts +4 -0
- package/src/types.ts +28 -0
- package/tests/conformance.spec.ts +41 -0
- package/tests/context.ts +103 -0
- package/tests/schema.spec.ts +187 -0
- package/tests/tables.spec.ts +89 -0
- package/tests/tsconfig.json +12 -0
- package/tsconfig.json +11 -0
package/README.md
CHANGED
|
@@ -1,3 +1,144 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @owlmeans/bot-postgres
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PostgreSQL storage for `@owlmeans/server-bot`: it registers the four resources the `BotService`
|
|
4
|
+
resolves by alias — `bot-connection`, `bot-rule`, `bot-update` (the inbox) and `bot-activity` — with
|
|
5
|
+
the shared AJV schemas and the indexes the service reads by. A Postgres-backed server (typically a
|
|
6
|
+
generated target project) adds it next to `appendBot`.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bun add @owlmeans/bot-postgres@^0.1.18-rc.2
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Peer dependencies: `pg`, `ajv`.
|
|
15
|
+
|
|
16
|
+
## Concepts
|
|
17
|
+
|
|
18
|
+
- **Four resources** — `BotConnectionResource`, `BotRuleResource`, `BotUpdateResource` and
|
|
19
|
+
`BotActivityResource`, each a `PostgresResource` of the matching `@owlmeans/server-bot` record, at
|
|
20
|
+
the aliases `RES_BOT_CONNECTION`, `RES_BOT_RULE`, `RES_BOT_UPDATE`, `RES_BOT_ACTIVITY`.
|
|
21
|
+
- **Shared schemas** — `resource.schema` is exactly `server-bot`'s record schema; this package
|
|
22
|
+
declares no schema of its own.
|
|
23
|
+
- **Column shapes** — nested objects (`identity`, the inbox `update`, the activity `target`) are one
|
|
24
|
+
`jsonb` column each; string lists (`keywords`, `setup`, `credentialsSet`, `handled`) are `text[]`;
|
|
25
|
+
timestamps are ISO `text`; the sealed credentials are one `text` column; the rule's `order` is a
|
|
26
|
+
quoted `double precision` column.
|
|
27
|
+
- **Unique inbox key** — `dedupe` carries a unique index, so a redelivered update is one row even
|
|
28
|
+
when two deliveries race.
|
|
29
|
+
- **Ids** — records are created without one; Postgres mints it.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Register the resources and the service
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { appendPostgres } from '@owlmeans/postgres'
|
|
37
|
+
import { appendPostgresBot } from '@owlmeans/bot-postgres'
|
|
38
|
+
import { appendBot } from '@owlmeans/server-bot'
|
|
39
|
+
|
|
40
|
+
appendPostgres(context) // the Postgres connection service, cfg.dbs[...]
|
|
41
|
+
appendPostgresBot(context) // the four resources
|
|
42
|
+
appendBot(context) // the service that resolves them by alias
|
|
43
|
+
|
|
44
|
+
await context.configure().init() // resource init reconciles tables and indexes (meta.autoSync, default Full)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`appendPostgresBot` skips a resource whose alias is already registered, so calling it twice is safe.
|
|
48
|
+
|
|
49
|
+
### Another database, connection service or alias set
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const resources = { connection: 'chat-connection', rule: 'chat-rule', update: 'chat-update', activity: 'chat-activity' }
|
|
53
|
+
|
|
54
|
+
appendPostgresBot(context, { dbAlias: 'bots', serviceAlias: 'postgres-secondary', resources })
|
|
55
|
+
appendBot(context, { resources })
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### One resource per file (a generated target)
|
|
59
|
+
|
|
60
|
+
The second maker argument is the resource alias, so a target's file wraps the maker into a
|
|
61
|
+
`ResourceMaker`:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// sources/backend/src/resources/bot/connection.ts
|
|
65
|
+
import { makeBotConnectionResource } from '@owlmeans/bot-postgres'
|
|
66
|
+
import type { BotConnectionResource } from '@owlmeans/bot-postgres'
|
|
67
|
+
import { RES_BOT_CONNECTION } from '@owlmeans/server-bot'
|
|
68
|
+
import type { BotConnectionRecord } from '@owlmeans/server-bot'
|
|
69
|
+
import type { ResourceMaker } from '@owlmeans/resource'
|
|
70
|
+
|
|
71
|
+
export const makeResource: ResourceMaker<BotConnectionRecord, BotConnectionResource> =
|
|
72
|
+
(dbAlias, serviceAlias) => makeBotConnectionResource(dbAlias, RES_BOT_CONNECTION, serviceAlias)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`rule.ts`, `update.ts` and `activity.ts` follow the same shape.
|
|
76
|
+
|
|
77
|
+
## API
|
|
78
|
+
|
|
79
|
+
| Symbol | Kind | Purpose |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `appendPostgresBot(ctx, opts?)` | function | Registers the four resources, each only if its alias is free |
|
|
82
|
+
| `makeBotConnectionResource(dbAlias?, alias?, serviceAlias?)` | function | `BotConnectionResource` |
|
|
83
|
+
| `makeBotRuleResource(dbAlias?, alias?, serviceAlias?)` | function | `BotRuleResource` |
|
|
84
|
+
| `makeBotUpdateResource(dbAlias?, alias?, serviceAlias?)` | function | `BotUpdateResource` (the inbox) |
|
|
85
|
+
| `makeBotActivityResource(dbAlias?, alias?, serviceAlias?)` | function | `BotActivityResource` |
|
|
86
|
+
| `BotPostgresOptions` | type | `{ dbAlias?, serviceAlias?, resources? }` |
|
|
87
|
+
|
|
88
|
+
### Indexes
|
|
89
|
+
|
|
90
|
+
Named `<table>_<suffix>`:
|
|
91
|
+
|
|
92
|
+
| Table | Suffix | Columns |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `bot_connection` | `scope_created` | `scope`, `createdAt` |
|
|
95
|
+
| `bot_connection` | `receive` | `enabled`, `status`, `receive` |
|
|
96
|
+
| `bot_rule` | `scope` | `scope` |
|
|
97
|
+
| `bot_rule` | `scope_connection` | `scope`, `connection` |
|
|
98
|
+
| `bot_update` | `dedupe` (unique) | `dedupe` |
|
|
99
|
+
| `bot_update` | `inbox` | `status`, `receivedAt` |
|
|
100
|
+
| `bot_update` | `lease` | `status`, `claimedAt` |
|
|
101
|
+
| `bot_update` | `connection_received` | `connection`, `receivedAt` |
|
|
102
|
+
| `bot_update` | `retention` | `status`, `processedAt` |
|
|
103
|
+
| `bot_activity` | `scope_at` | `scope`, `at` |
|
|
104
|
+
| `bot_activity` | `scope_connection_at` | `scope`, `connection`, `at` |
|
|
105
|
+
|
|
106
|
+
## Testing
|
|
107
|
+
|
|
108
|
+
`tests/schema.spec.ts` needs no database: it compiles the shared schemas and asserts the column
|
|
109
|
+
types, the quoted `order` column, the declared indexes and idempotent registration.
|
|
110
|
+
`tests/conformance.spec.ts` (the `@owlmeans/server-bot/conformance` store suite, every case including
|
|
111
|
+
the unique one) and `tests/tables.spec.ts` (a second boot plans no DDL; the round trips) are
|
|
112
|
+
integration suites gated on `POSTGRES_URL`; they skip without one.
|
|
113
|
+
|
|
114
|
+
## Common pitfalls
|
|
115
|
+
|
|
116
|
+
- Using a maker directly as a `ResourceMaker` — its second argument is the resource alias, not the
|
|
117
|
+
service alias.
|
|
118
|
+
- Registering custom aliases here but not on `appendBot` — the service looks the defaults up and fails.
|
|
119
|
+
- Redeclaring a schema locally — the table would drift from what the service reads and writes.
|
|
120
|
+
|
|
121
|
+
The `bot-postgres` skill covers this package; the `server-bot` skill covers the records and the service.
|
|
122
|
+
|
|
123
|
+
## Related packages
|
|
124
|
+
|
|
125
|
+
- [`@owlmeans/server-bot`](../server-bot) — the service, record types, schemas, aliases and the conformance suite
|
|
126
|
+
- [`@owlmeans/bot`](../bot) — the chat-bot contract
|
|
127
|
+
- [`@owlmeans/postgres-resource`](../postgres-resource) — `makePostgresResource`, `index()`, the schema-to-table compiler
|
|
128
|
+
- [`@owlmeans/postgres`](../postgres) — `appendPostgres`, the connection service
|
|
129
|
+
|
|
130
|
+
<!-- owlmeans:agent-guidance:start -->
|
|
131
|
+
## Agent guidance
|
|
132
|
+
|
|
133
|
+
This package ships embedded agent skills under `agent-meta/`. After installing your
|
|
134
|
+
`@owlmeans/*` packages, run the OwlMeans agent-skills installer to place them into
|
|
135
|
+
your project's skill store (`.agents/skills/`):
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.59
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The embedded files are version-matched to this package release. Do not edit them
|
|
142
|
+
directly — they are regenerated on each publish. To contribute guidance edits,
|
|
143
|
+
open a PR against the source monorepo.
|
|
144
|
+
<!-- owlmeans:agent-guidance:end -->
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 3,
|
|
3
|
+
"package": "@owlmeans/bot-postgres",
|
|
4
|
+
"version": "0.1.18-rc.2",
|
|
5
|
+
"generatedAt": "2026-10-26T22:23:53.840Z",
|
|
6
|
+
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "skill",
|
|
10
|
+
"name": "bot-postgres",
|
|
11
|
+
"category": "package-specific",
|
|
12
|
+
"file": "skills/bot-postgres/SKILL.md",
|
|
13
|
+
"canonicalPath": ".agents/skills/bot-postgres/SKILL.md"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bot-postgres
|
|
3
|
+
description: How to use @owlmeans/bot-postgres — the Postgres extension that registers the four @owlmeans/server-bot resources (bot-connection, bot-rule, bot-update, bot-activity) for a GENERATED TARGET PROJECT, their table shapes and indexes, the unique inbox dedupe key, and the target's resource seed files. Auto-invoked when wiring bot storage into a target's Postgres backend, writing a target's resources/bot/*.ts, or touching the bot tables' shape or indexes.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
|
+
|
|
8
|
+
# @owlmeans/bot-postgres
|
|
9
|
+
|
|
10
|
+
**Layer:** Infra extension
|
|
11
|
+
**Install:** `"@owlmeans/bot-postgres": "^0.1.18-rc.2"` in `dependencies` (peers `pg`, `ajv`)
|
|
12
|
+
|
|
13
|
+
The Postgres store of `@owlmeans/server-bot`: four `@owlmeans/postgres-resource` resources over the
|
|
14
|
+
record schemas `server-bot` declares, plus the indexes its reads need. It owns no bot behaviour — the
|
|
15
|
+
`BotService` resolves the four by alias on every call, so this package and `appendBot` are registered
|
|
16
|
+
independently, in any order.
|
|
17
|
+
|
|
18
|
+
## Key Exports
|
|
19
|
+
|
|
20
|
+
| Export | Description |
|
|
21
|
+
|--------|-------------|
|
|
22
|
+
| `makeBotConnectionResource(dbAlias?, alias?, serviceAlias?)` | `BotConnectionResource` (`PostgresResource<BotConnectionRecord>`), alias default `RES_BOT_CONNECTION` |
|
|
23
|
+
| `makeBotRuleResource(dbAlias?, alias?, serviceAlias?)` | `BotRuleResource`, default `RES_BOT_RULE` |
|
|
24
|
+
| `makeBotUpdateResource(dbAlias?, alias?, serviceAlias?)` | `BotUpdateResource` — the inbox, default `RES_BOT_UPDATE` |
|
|
25
|
+
| `makeBotActivityResource(dbAlias?, alias?, serviceAlias?)` | `BotActivityResource`, default `RES_BOT_ACTIVITY` |
|
|
26
|
+
| `appendPostgresBot(ctx, opts?)` | Registers the four, each only while its alias is free — idempotent |
|
|
27
|
+
| `BotPostgresOptions` | `{ dbAlias?, serviceAlias?, resources?: BotResourceAliases }` |
|
|
28
|
+
|
|
29
|
+
`dbAlias` is the `cfg.dbs` entry (default `postgres`), `serviceAlias` the connection service (default
|
|
30
|
+
`postgres`). The second argument is the RESOURCE alias, not the service alias — so a maker is not a
|
|
31
|
+
`ResourceMaker` as is; a target file wraps it (below).
|
|
32
|
+
|
|
33
|
+
## The schema is imported, never redeclared
|
|
34
|
+
|
|
35
|
+
Each maker assigns `BotConnectionRecordSchema` / `BotRuleRecordSchema` / `BotUpdateRecordSchema` /
|
|
36
|
+
`BotActivityRecordSchema` from `@owlmeans/server-bot` to `resource.schema` — the same object, never a
|
|
37
|
+
copy, and no `pg:` override. A change to a record is a change to `server-bot`'s schema; this package
|
|
38
|
+
follows it at the next boot (`PgAutoSync.Full` reconciles the table).
|
|
39
|
+
|
|
40
|
+
## Table shapes
|
|
41
|
+
|
|
42
|
+
What `postgres-resource`'s default compiler makes of the shared schemas (`tests/schema.spec.ts` pins it):
|
|
43
|
+
|
|
44
|
+
| Values | Column | Properties |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| nested objects | one `jsonb` column each | `identity`, the inbox `update` (open: `raw` is the platform's payload), the activity `target` |
|
|
47
|
+
| string lists | native `text[]` | `setup`, `credentialsSet`, `keywords`, `handled` |
|
|
48
|
+
| timestamps | `text` (ISO, sortable as stored — no `format`, so never `timestamptz`) | `createdAt`, `updatedAt`, `receivedAt`, `claimedAt`, `retryAt`, `processedAt`, `at` |
|
|
49
|
+
| sealed credentials | ONE `text` column, never split per credential key | `sealed` (`v1.<iv>.<tag>.<ciphertext>`) |
|
|
50
|
+
| enums | `text` + `CHECK` | `platform`, `transport`, `status`, `receive`, `mode`, `action` |
|
|
51
|
+
| `order` (a reserved word) | `double precision`, quoted wherever the store names it | rule `order` |
|
|
52
|
+
|
|
53
|
+
Records are created without an `id` (Postgres mints `gen_random_uuid()::text`); `update`/`save` with an
|
|
54
|
+
id REPLACES the whole row. Absent optional fields come back `null`; the service reads `null` as absent.
|
|
55
|
+
|
|
56
|
+
## Indexes
|
|
57
|
+
|
|
58
|
+
Index names are `<table>_<suffix>`, so a second set of bot tables under custom aliases in the same
|
|
59
|
+
schema never collides; a maker run twice declares each index once.
|
|
60
|
+
|
|
61
|
+
| Table | Index | Columns | Serves |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `bot_connection` | `scope_created` | `scope`, `createdAt` | a scope's connections in order |
|
|
64
|
+
| `bot_connection` | `receive` | `enabled`, `status`, `receive` | the worker's receiver reconciliation |
|
|
65
|
+
| `bot_rule` | `scope` | `scope` | a scope's rules |
|
|
66
|
+
| `bot_rule` | `scope_connection` | `scope`, `connection` | a connection's own rules, the remove cascade |
|
|
67
|
+
| `bot_update` | `dedupe` **UNIQUE** | `dedupe` | one row per redelivered update |
|
|
68
|
+
| `bot_update` | `inbox` | `status`, `receivedAt` | pending rows, oldest first |
|
|
69
|
+
| `bot_update` | `lease` | `status`, `claimedAt` | expired `processing` claims |
|
|
70
|
+
| `bot_update` | `connection_received` | `connection`, `receivedAt` | a connection's newest update, its inbox purge |
|
|
71
|
+
| `bot_update` | `retention` | `status`, `processedAt` | the purge of old `done` rows |
|
|
72
|
+
| `bot_activity` | `scope_at` | `scope`, `at` | the activity feed, newest first |
|
|
73
|
+
| `bot_activity` | `scope_connection_at` | `scope`, `connection`, `at` | one connection's feed |
|
|
74
|
+
|
|
75
|
+
The unique `dedupe` is the store's backstop against two concurrent deliveries: the loser's `create`
|
|
76
|
+
throws `RecordExists` and the service reads the stored row back. It is what qualifies this store for
|
|
77
|
+
the conformance suite's `unique` capability.
|
|
78
|
+
|
|
79
|
+
## Target wiring
|
|
80
|
+
|
|
81
|
+
**Backs:** chat-bot connections with sealed credentials, keyword rules, the inbound update inbox and the bots' activity log
|
|
82
|
+
|
|
83
|
+
| Sub-project | Packages |
|
|
84
|
+
|---|---|
|
|
85
|
+
| backend | `@owlmeans/bot-postgres`, `@owlmeans/server-bot`, `@owlmeans/bot` |
|
|
86
|
+
|
|
87
|
+
One file per resource under `sources/backend/src/resources/bot/`: the generated registry imports each
|
|
88
|
+
file's zero-argument `makeResource` and registers it before `init()` creates the table. The path
|
|
89
|
+
names the alias (`bot/connection.ts` → `bot-connection`), which is exactly `server-bot`'s default, so
|
|
90
|
+
`appendBot(context)` needs no `resources` option. The bot service itself, the api trees and the
|
|
91
|
+
worker runtime are `server-bot`'s wiring.
|
|
92
|
+
|
|
93
|
+
```ts file=sources/backend/src/resources/bot/connection.ts
|
|
94
|
+
import { makeBotConnectionResource } from '@owlmeans/bot-postgres'
|
|
95
|
+
import type { BotConnectionResource } from '@owlmeans/bot-postgres'
|
|
96
|
+
import { RES_BOT_CONNECTION } from '@owlmeans/server-bot'
|
|
97
|
+
import type { BotConnectionRecord } from '@owlmeans/server-bot'
|
|
98
|
+
import type { ResourceMaker } from '@owlmeans/resource'
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The bot's connections (`bot-connection`) — credentials sealed with APP_SECRET, never stored in
|
|
102
|
+
* clear. The maker is a thin wrapper: the schema and indexes are the package's own.
|
|
103
|
+
*/
|
|
104
|
+
export const makeResource: ResourceMaker<BotConnectionRecord, BotConnectionResource> =
|
|
105
|
+
(dbAlias, serviceAlias) => makeBotConnectionResource(dbAlias, RES_BOT_CONNECTION, serviceAlias)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```ts file=sources/backend/src/resources/bot/rule.ts
|
|
109
|
+
import { makeBotRuleResource } from '@owlmeans/bot-postgres'
|
|
110
|
+
import type { BotRuleResource } from '@owlmeans/bot-postgres'
|
|
111
|
+
import { RES_BOT_RULE } from '@owlmeans/server-bot'
|
|
112
|
+
import type { BotRuleRecord } from '@owlmeans/server-bot'
|
|
113
|
+
import type { ResourceMaker } from '@owlmeans/resource'
|
|
114
|
+
|
|
115
|
+
/** The keyword rules (`bot-rule`) — scope-wide or bound to one connection, kept in `order`. */
|
|
116
|
+
export const makeResource: ResourceMaker<BotRuleRecord, BotRuleResource> =
|
|
117
|
+
(dbAlias, serviceAlias) => makeBotRuleResource(dbAlias, RES_BOT_RULE, serviceAlias)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```ts file=sources/backend/src/resources/bot/update.ts
|
|
121
|
+
import { makeBotUpdateResource } from '@owlmeans/bot-postgres'
|
|
122
|
+
import type { BotUpdateResource } from '@owlmeans/bot-postgres'
|
|
123
|
+
import { RES_BOT_UPDATE } from '@owlmeans/server-bot'
|
|
124
|
+
import type { BotUpdateRecord } from '@owlmeans/server-bot'
|
|
125
|
+
import type { ResourceMaker } from '@owlmeans/resource'
|
|
126
|
+
|
|
127
|
+
/** The inbox (`bot-update`) — one row per inbound update, unique by its dedupe key; the worker drains it. */
|
|
128
|
+
export const makeResource: ResourceMaker<BotUpdateRecord, BotUpdateResource> =
|
|
129
|
+
(dbAlias, serviceAlias) => makeBotUpdateResource(dbAlias, RES_BOT_UPDATE, serviceAlias)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```ts file=sources/backend/src/resources/bot/activity.ts
|
|
133
|
+
import { makeBotActivityResource } from '@owlmeans/bot-postgres'
|
|
134
|
+
import type { BotActivityResource } from '@owlmeans/bot-postgres'
|
|
135
|
+
import { RES_BOT_ACTIVITY } from '@owlmeans/server-bot'
|
|
136
|
+
import type { BotActivityRecord } from '@owlmeans/server-bot'
|
|
137
|
+
import type { ResourceMaker } from '@owlmeans/resource'
|
|
138
|
+
|
|
139
|
+
/** What every bot action did (`bot-activity`) — kept when its connection is removed. */
|
|
140
|
+
export const makeResource: ResourceMaker<BotActivityRecord, BotActivityResource> =
|
|
141
|
+
(dbAlias, serviceAlias) => makeBotActivityResource(dbAlias, RES_BOT_ACTIVITY, serviceAlias)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
All four are required: the service reads and writes every one of them. Never pass a maker to
|
|
145
|
+
`ResourceMaker` directly (`makeResource = makeBotConnectionResource`) — a caller's `serviceAlias`
|
|
146
|
+
would land in the resource-alias position.
|
|
147
|
+
|
|
148
|
+
## Wiring outside a target
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { appendPostgres } from '@owlmeans/postgres'
|
|
152
|
+
import { appendPostgresBot } from '@owlmeans/bot-postgres'
|
|
153
|
+
import { appendBot } from '@owlmeans/server-bot'
|
|
154
|
+
|
|
155
|
+
appendPostgres(context) // the connection service, cfg.dbs[...]
|
|
156
|
+
appendPostgresBot(context) // the four resources
|
|
157
|
+
appendBot(context) // the service, which resolves them by alias per call
|
|
158
|
+
await context.configure().init() // init reconciles the four tables and their indexes
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Custom aliases go to both sides:
|
|
162
|
+
`appendPostgresBot(ctx, { resources })` and `appendBot(ctx, { resources })`.
|
|
163
|
+
|
|
164
|
+
## Testing
|
|
165
|
+
|
|
166
|
+
Category C. `bun test ./tests`: `schema.spec.ts` needs no database (the column types, the quoted
|
|
167
|
+
`order`, the declared indexes, the unique dedupe DDL, idempotent registration); `conformance.spec.ts`
|
|
168
|
+
runs `server-bot`'s store suite — `botConformanceCasesFor(['unique'])` over
|
|
169
|
+
`makeBotConformanceSubject(context)`, every case — and `tables.spec.ts` asserts a second boot plans
|
|
170
|
+
no DDL and round-trips the jsonb, `text[]` and `order` columns. Both are gated on `POSTGRES_URL`
|
|
171
|
+
(`gateHelper.postgresGate()`, each spec file its own throwaway schema) and skip cleanly without it.
|
|
172
|
+
With no database of this checkout's own, run them against a throwaway container
|
|
173
|
+
(`docker run --rm -d -p 127.0.0.1:<port>:5432 -e POSTGRES_PASSWORD=… postgres:<tag>`) — never another
|
|
174
|
+
slot's test database. A new conformance case runs here only after `server-bot` is rebuilt.
|
|
175
|
+
|
|
176
|
+
## Related
|
|
177
|
+
|
|
178
|
+
- `server-bot` — the service, the record types and schemas, the aliases, the conformance suite (read its skill first)
|
|
179
|
+
- `bot` — the contract the records carry (platforms, statuses, enums)
|
|
180
|
+
- `postgres-resource` — the table compiler, `index()`, the reconciliation · `postgres` — the connection service
|
|
181
|
+
- `marketing-consent-postgres`, `planning-postgres` — the same import-the-schema pattern for other features
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BasicContext } from '@owlmeans/context';
|
|
2
|
+
import type { BotPostgresOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Registers the four bot resources, each only while its alias is free — a second call (a context
|
|
5
|
+
* composed in two places, a hot reload) leaves the registered ones alone. Registration order against
|
|
6
|
+
* `appendBot` is free: the service resolves its resources by alias on every call.
|
|
7
|
+
*/
|
|
8
|
+
export declare const appendPostgresBot: (ctx: BasicContext<any>, opts?: BotPostgresOptions) => void;
|
|
9
|
+
//# sourceMappingURL=helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAMrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAS,YAAY,CAAC,GAAG,CAAC,SAAQ,kBAAkB,KAAQ,IAmBzF,CAAA"}
|
package/build/helper.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RES_BOT_ACTIVITY, RES_BOT_CONNECTION, RES_BOT_RULE, RES_BOT_UPDATE } from '@owlmeans/server-bot';
|
|
2
|
+
import { makeBotActivityResource, makeBotConnectionResource, makeBotRuleResource, makeBotUpdateResource, } from './resource.js';
|
|
3
|
+
/**
|
|
4
|
+
* Registers the four bot resources, each only while its alias is free — a second call (a context
|
|
5
|
+
* composed in two places, a hot reload) leaves the registered ones alone. Registration order against
|
|
6
|
+
* `appendBot` is free: the service resolves its resources by alias on every call.
|
|
7
|
+
*/
|
|
8
|
+
export const appendPostgresBot = (ctx, opts = {}) => {
|
|
9
|
+
const { dbAlias, serviceAlias, resources = {} } = opts;
|
|
10
|
+
const connection = resources.connection ?? RES_BOT_CONNECTION;
|
|
11
|
+
const rule = resources.rule ?? RES_BOT_RULE;
|
|
12
|
+
const update = resources.update ?? RES_BOT_UPDATE;
|
|
13
|
+
const activity = resources.activity ?? RES_BOT_ACTIVITY;
|
|
14
|
+
if (!ctx.hasResource(connection)) {
|
|
15
|
+
ctx.registerResource(makeBotConnectionResource(dbAlias, connection, serviceAlias));
|
|
16
|
+
}
|
|
17
|
+
if (!ctx.hasResource(rule)) {
|
|
18
|
+
ctx.registerResource(makeBotRuleResource(dbAlias, rule, serviceAlias));
|
|
19
|
+
}
|
|
20
|
+
if (!ctx.hasResource(update)) {
|
|
21
|
+
ctx.registerResource(makeBotUpdateResource(dbAlias, update, serviceAlias));
|
|
22
|
+
}
|
|
23
|
+
if (!ctx.hasResource(activity)) {
|
|
24
|
+
ctx.registerResource(makeBotActivityResource(dbAlias, activity, serviceAlias));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAEzG,OAAO,EACL,uBAAuB,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,qBAAqB,GAC/F,MAAM,eAAe,CAAA;AAGtB;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAsB,EAAE,IAAI,GAAuB,EAAE,EAAQ,EAAE;IAC/F,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,GAAG,EAAE,EAAE,GAAG,IAAI,CAAA;IACtD,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,IAAI,kBAAkB,CAAA;IAC7D,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,YAAY,CAAA;IAC3C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,cAAc,CAAA;IACjD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,gBAAgB,CAAA;IAEvD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,GAAG,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAA;IACpF,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,GAAG,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAA;IACxE,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;IAC5E,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAA;IAChF,CAAC;AACH,CAAC,CAAA"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BotActivityResource, BotConnectionResource, BotRuleResource, BotUpdateResource } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `bot-connection` — the connections of every scope. The schema is `server-bot`'s own, assigned, never
|
|
4
|
+
* copied: `identity` compiles to one `jsonb` column, `setup` and `credentialsSet` to `text[]`, the
|
|
5
|
+
* sealed credentials to one `text` column. Indexes follow the reads: a scope's list by creation, and
|
|
6
|
+
* the worker's reconciliation (enabled, connected, polling or on the gateway).
|
|
7
|
+
*/
|
|
8
|
+
export declare const makeBotConnectionResource: (dbAlias?: string, alias?: string, serviceAlias?: string) => BotConnectionResource;
|
|
9
|
+
/**
|
|
10
|
+
* `bot-rule` — keyword rules, scope-wide (`connection` null) or bound to one connection; `keywords` is
|
|
11
|
+
* `text[]`, `order` a `double precision` column (quoted wherever the store names it).
|
|
12
|
+
*/
|
|
13
|
+
export declare const makeBotRuleResource: (dbAlias?: string, alias?: string, serviceAlias?: string) => BotRuleResource;
|
|
14
|
+
/**
|
|
15
|
+
* `bot-update` — the inbox. `dedupe` is UNIQUE: two concurrent deliveries of one platform update
|
|
16
|
+
* collide here (`RecordExists`) and the service reads the stored row back. The normalized `update`
|
|
17
|
+
* is one `jsonb` column, `handled` a `text[]`. Indexes follow the dispatcher (pending rows by age,
|
|
18
|
+
* expired leases), a connection's newest update, and the retention purge.
|
|
19
|
+
*/
|
|
20
|
+
export declare const makeBotUpdateResource: (dbAlias?: string, alias?: string, serviceAlias?: string) => BotUpdateResource;
|
|
21
|
+
/** `bot-activity` — what every action did; `target` is one `jsonb` column. Read newest first per scope. */
|
|
22
|
+
export declare const makeBotActivityResource: (dbAlias?: string, alias?: string, serviceAlias?: string) => BotActivityResource;
|
|
23
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAoBhH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,aAC1B,MAAM,UAAS,MAAM,iBAAsC,MAAM,KAC1E,qBASF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,aACpB,MAAM,UAAS,MAAM,iBAAgC,MAAM,KACpE,eASF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,aACtB,MAAM,UAAS,MAAM,iBAAkC,MAAM,KACtE,iBAYF,CAAA;AAED,2GAA2G;AAC3G,eAAO,MAAM,uBAAuB,aACxB,MAAM,UAAS,MAAM,iBAAoC,MAAM,KACxE,mBASF,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { makePostgresResource, pgDeclarationHelper, pgNameHelper } from '@owlmeans/postgres-resource';
|
|
2
|
+
import { BotActivityRecordSchema, BotConnectionRecordSchema, BotRuleRecordSchema, BotUpdateRecordSchema, RES_BOT_ACTIVITY, RES_BOT_CONNECTION, RES_BOT_RULE, RES_BOT_UPDATE, } from '@owlmeans/server-bot';
|
|
3
|
+
/**
|
|
4
|
+
* Declare the indexes a maker owns, each once. Declarations are kept per alias at module scope, so a
|
|
5
|
+
* maker that runs twice (a target's file wrapping it, a spec) would otherwise declare every index
|
|
6
|
+
* again and the compiler would warn about the duplicate on every boot. The name carries the table,
|
|
7
|
+
* so a second set of bot tables under other aliases in the same schema never collides with the first.
|
|
8
|
+
*/
|
|
9
|
+
const declareIndexes = (resource, alias, indexes) => {
|
|
10
|
+
const table = pgNameHelper.pgIdentifier(alias);
|
|
11
|
+
const declared = pgDeclarationHelper.getDeclaration(alias).indexes;
|
|
12
|
+
for (const [suffix, spec] of indexes) {
|
|
13
|
+
const name = `${table}_${suffix}`;
|
|
14
|
+
if (!declared.some(index => index.name === name)) {
|
|
15
|
+
resource.index(name, spec);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* `bot-connection` — the connections of every scope. The schema is `server-bot`'s own, assigned, never
|
|
21
|
+
* copied: `identity` compiles to one `jsonb` column, `setup` and `credentialsSet` to `text[]`, the
|
|
22
|
+
* sealed credentials to one `text` column. Indexes follow the reads: a scope's list by creation, and
|
|
23
|
+
* the worker's reconciliation (enabled, connected, polling or on the gateway).
|
|
24
|
+
*/
|
|
25
|
+
export const makeBotConnectionResource = (dbAlias, alias = RES_BOT_CONNECTION, serviceAlias) => {
|
|
26
|
+
const resource = makePostgresResource(alias, dbAlias, serviceAlias);
|
|
27
|
+
resource.schema = BotConnectionRecordSchema;
|
|
28
|
+
declareIndexes(resource, alias, [
|
|
29
|
+
['scope_created', { columns: ['scope', 'createdAt'] }],
|
|
30
|
+
['receive', { columns: ['enabled', 'status', 'receive'] }],
|
|
31
|
+
]);
|
|
32
|
+
return resource;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* `bot-rule` — keyword rules, scope-wide (`connection` null) or bound to one connection; `keywords` is
|
|
36
|
+
* `text[]`, `order` a `double precision` column (quoted wherever the store names it).
|
|
37
|
+
*/
|
|
38
|
+
export const makeBotRuleResource = (dbAlias, alias = RES_BOT_RULE, serviceAlias) => {
|
|
39
|
+
const resource = makePostgresResource(alias, dbAlias, serviceAlias);
|
|
40
|
+
resource.schema = BotRuleRecordSchema;
|
|
41
|
+
declareIndexes(resource, alias, [
|
|
42
|
+
['scope', { columns: ['scope'] }],
|
|
43
|
+
['scope_connection', { columns: ['scope', 'connection'] }],
|
|
44
|
+
]);
|
|
45
|
+
return resource;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* `bot-update` — the inbox. `dedupe` is UNIQUE: two concurrent deliveries of one platform update
|
|
49
|
+
* collide here (`RecordExists`) and the service reads the stored row back. The normalized `update`
|
|
50
|
+
* is one `jsonb` column, `handled` a `text[]`. Indexes follow the dispatcher (pending rows by age,
|
|
51
|
+
* expired leases), a connection's newest update, and the retention purge.
|
|
52
|
+
*/
|
|
53
|
+
export const makeBotUpdateResource = (dbAlias, alias = RES_BOT_UPDATE, serviceAlias) => {
|
|
54
|
+
const resource = makePostgresResource(alias, dbAlias, serviceAlias);
|
|
55
|
+
resource.schema = BotUpdateRecordSchema;
|
|
56
|
+
declareIndexes(resource, alias, [
|
|
57
|
+
['dedupe', { columns: ['dedupe'], unique: true }],
|
|
58
|
+
['inbox', { columns: ['status', 'receivedAt'] }],
|
|
59
|
+
['lease', { columns: ['status', 'claimedAt'] }],
|
|
60
|
+
['connection_received', { columns: ['connection', 'receivedAt'] }],
|
|
61
|
+
['retention', { columns: ['status', 'processedAt'] }],
|
|
62
|
+
]);
|
|
63
|
+
return resource;
|
|
64
|
+
};
|
|
65
|
+
/** `bot-activity` — what every action did; `target` is one `jsonb` column. Read newest first per scope. */
|
|
66
|
+
export const makeBotActivityResource = (dbAlias, alias = RES_BOT_ACTIVITY, serviceAlias) => {
|
|
67
|
+
const resource = makePostgresResource(alias, dbAlias, serviceAlias);
|
|
68
|
+
resource.schema = BotActivityRecordSchema;
|
|
69
|
+
declareIndexes(resource, alias, [
|
|
70
|
+
['scope_at', { columns: ['scope', 'at'] }],
|
|
71
|
+
['scope_connection_at', { columns: ['scope', 'connection', 'at'] }],
|
|
72
|
+
]);
|
|
73
|
+
return resource;
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PostgresResource } from '@owlmeans/postgres-resource';
|
|
2
|
+
import type { BotActivityRecord, BotConnectionRecord, BotResourceAliases, BotRuleRecord, BotUpdateRecord } from '@owlmeans/server-bot';
|
|
3
|
+
/** `bot-connection` — one row per connected bot, its credentials sealed in one text column. */
|
|
4
|
+
export interface BotConnectionResource extends PostgresResource<BotConnectionRecord> {
|
|
5
|
+
}
|
|
6
|
+
/** `bot-rule` — the keyword rules of a scope, scope-wide or bound to one connection. */
|
|
7
|
+
export interface BotRuleResource extends PostgresResource<BotRuleRecord> {
|
|
8
|
+
}
|
|
9
|
+
/** `bot-update` — the inbox: one row per inbound platform update, unique by its `dedupe` key. */
|
|
10
|
+
export interface BotUpdateResource extends PostgresResource<BotUpdateRecord> {
|
|
11
|
+
}
|
|
12
|
+
/** `bot-activity` — one row per action a bot took (or refused), newest read first. */
|
|
13
|
+
export interface BotActivityResource extends PostgresResource<BotActivityRecord> {
|
|
14
|
+
}
|
|
15
|
+
export interface BotPostgresOptions {
|
|
16
|
+
/** The `cfg.dbs` entry the four tables live in — default `postgres`. */
|
|
17
|
+
dbAlias?: string;
|
|
18
|
+
/** The Postgres connection service — default `postgres`. */
|
|
19
|
+
serviceAlias?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The resources' aliases — default `bot-connection`, `bot-rule`, `bot-update`, `bot-activity`.
|
|
22
|
+
* The bot service must be given the same ones (`appendBot(ctx, { resources })`).
|
|
23
|
+
*/
|
|
24
|
+
resources?: BotResourceAliases;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EACV,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,aAAa,EAAE,eAAe,EAC3F,MAAM,sBAAsB,CAAA;AAE7B,+FAA+F;AAC/F,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB,CAAC,mBAAmB,CAAC;CAAG;AAEvF,wFAAwF;AACxF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB,CAAC,aAAa,CAAC;CAAG;AAE3E,iGAAiG;AACjG,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB,CAAC,eAAe,CAAC;CAAG;AAE/E,sFAAsF;AACtF,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB,CAAC,iBAAiB,CAAC;CAAG;AAEnF,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAA;CAC/B"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PgIndexSpec } from '@owlmeans/postgres-resource';
|
|
2
|
+
/** The indexes a maker owns, by name suffix — the full name is `<table>_<suffix>`. */
|
|
3
|
+
export type IndexList = ReadonlyArray<readonly [suffix: string, spec: PgIndexSpec]>;
|
|
4
|
+
//# sourceMappingURL=types.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE9D,sFAAsF;AACtF,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.js","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/bot-postgres",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.18-rc.2",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Postgres-backed resources for @owlmeans/server-bot — the connection, rule, inbox and activity tables of a generated target project, compiled from the shared AJV schemas, with the unique inbox dedupe key.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -b",
|
|
9
|
+
"dev": "sleep 14 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
|
|
10
|
+
"watch": "tsc -b -w --preserveWatchOutput --pretty",
|
|
11
|
+
"test": "bun test ./tests"
|
|
12
|
+
},
|
|
13
|
+
"main": "build/index.js",
|
|
14
|
+
"module": "build/index.js",
|
|
15
|
+
"types": "build/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./build/index.js",
|
|
19
|
+
"require": "./build/index.js",
|
|
20
|
+
"default": "./build/index.js",
|
|
21
|
+
"module": "./build/index.js",
|
|
22
|
+
"types": "./build/index.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@owlmeans/context": "^0.1.18-rc.35",
|
|
27
|
+
"@owlmeans/postgres-resource": "^0.1.18-rc.50",
|
|
28
|
+
"@owlmeans/resource": "^0.1.18-rc.41",
|
|
29
|
+
"@owlmeans/server-bot": "^0.1.18-rc.2"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"ajv": "*",
|
|
33
|
+
"pg": "*"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@owlmeans/bot": "^0.1.18-rc.2",
|
|
37
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
38
|
+
"@owlmeans/log": "^0.1.18-rc.4",
|
|
39
|
+
"@owlmeans/postgres": "^0.1.18-rc.52",
|
|
40
|
+
"@owlmeans/server-context": "^0.1.18-rc.45",
|
|
41
|
+
"@owlmeans/test": "^0.1.18-rc.39",
|
|
42
|
+
"@owlmeans/test-integration": "^0.1.18-rc.37",
|
|
43
|
+
"@types/bun": "^1.4.2",
|
|
44
|
+
"@types/node": "^26.6.4",
|
|
45
|
+
"@types/pg": "^8.23.1",
|
|
46
|
+
"ajv": "^8.20.0",
|
|
47
|
+
"nodemon": "^3.1.14",
|
|
48
|
+
"pg": "^8.23.1",
|
|
49
|
+
"typescript": "^7.0.2"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
}
|
|
54
|
+
}
|