@clude/sdk 3.0.4 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +3992 -661
- package/dist/mcp/local-store.d.ts +74 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +2450 -274
- package/dist/sdk/cortex-v2.d.ts +120 -0
- package/dist/sdk/cortex.d.ts +63 -0
- package/dist/sdk/http-transport.d.ts +14 -0
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +2523 -408
- package/dist/sdk/memory-types.d.ts +321 -0
- package/dist/sdk/sdk-mode.d.ts +1 -0
- package/dist/sdk/shared-constants.d.ts +53 -0
- package/dist/sdk/types.d.ts +47 -0
- package/package.json +8 -17
- package/supabase-schema.sql +276 -12
package/supabase-schema.sql
CHANGED
|
@@ -89,14 +89,47 @@ CREATE TABLE IF NOT EXISTS memories (
|
|
|
89
89
|
compacted_into TEXT, -- hash_id of the memory this was compacted into
|
|
90
90
|
encrypted BOOLEAN DEFAULT FALSE, -- whether content is client-side encrypted
|
|
91
91
|
encryption_pubkey TEXT, -- Solana pubkey that encrypted this memory
|
|
92
|
+
provider_delegated BOOLEAN DEFAULT TRUE, -- envelope: provider may read while delegated; revoke flips to FALSE (encryption §7)
|
|
93
|
+
summary_ciphertext TEXT, -- secretbox(summary) — populated on revoke (§9)
|
|
94
|
+
embedding_ciphertext TEXT, -- secretbox(embedding) — populated on revoke (§9)
|
|
92
95
|
owner_wallet TEXT, -- Solana pubkey of the memory owner
|
|
93
96
|
event_date TIMESTAMPTZ DEFAULT NULL, -- explicit event date extracted from content (temporal indexing)
|
|
94
97
|
event_date_precision TEXT DEFAULT NULL CHECK (event_date_precision IN ('day', 'week', 'month', 'year')),
|
|
95
98
|
ts_summary tsvector GENERATED ALWAYS AS (
|
|
96
|
-
setweight(to_tsvector('english', COALESCE(summary, '')), 'A')
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
setweight(to_tsvector('english', COALESCE(summary, '')), 'A')
|
|
100
|
+
) STORED, -- summary-only lexemes; content lexemes live in content_tokens (encryption §9)
|
|
101
|
+
content_tokens tsvector, -- content lexemes, app-maintained via set_memory_content_tokens; cleared on revoke
|
|
102
|
+
-- Memory 3.0 Phase 1 (migration 044): bi-temporal validity + provenance (all nullable, inert until MEMORY_RECONCILE)
|
|
103
|
+
valid_from TIMESTAMPTZ, -- fact lifetime start (defaults to created_at at reconcile time)
|
|
104
|
+
invalid_at TIMESTAMPTZ, -- NULL = currently valid; set = superseded/retired (never DELETE)
|
|
105
|
+
superseded_by TEXT, -- hash_id of the memory that replaced this one
|
|
106
|
+
fact_key TEXT, -- (entity, attribute) reconciliation key
|
|
107
|
+
extractor_version TEXT, -- provenance: which extractor produced this
|
|
108
|
+
extraction_confidence REAL, -- 0..1 extractor confidence
|
|
109
|
+
source_turn_ref JSONB, -- pointer back to the source conversation turn
|
|
110
|
+
hash_id_v2 TEXT -- 16-byte server-minted id (dual identity; legacy hash_id untouched)
|
|
99
111
|
);
|
|
112
|
+
-- Phase 1 hot-path indexes: recall filters to currently-valid rows; reconciliation groups by fact_key.
|
|
113
|
+
CREATE INDEX IF NOT EXISTS idx_memories_valid ON memories(id) WHERE invalid_at IS NULL;
|
|
114
|
+
CREATE INDEX IF NOT EXISTS idx_memories_fact_key ON memories(fact_key) WHERE fact_key IS NOT NULL;
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_memories_hash_id_v2 ON memories(hash_id_v2) WHERE hash_id_v2 IS NOT NULL;
|
|
116
|
+
|
|
117
|
+
-- Memory 3.0 Phase 1 (migration 044): the C2 durable write outbox — replaces the
|
|
118
|
+
-- fire-and-forget embed/link/extract triad (errors were silently swallowed).
|
|
119
|
+
CREATE TABLE IF NOT EXISTS memory_write_jobs (
|
|
120
|
+
id BIGSERIAL PRIMARY KEY,
|
|
121
|
+
memory_id BIGINT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
122
|
+
job_type TEXT NOT NULL CHECK (job_type IN ('embed', 'link', 'extract', 'reconcile', 'backfill_v2')),
|
|
123
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'running', 'done', 'failed')),
|
|
124
|
+
attempts INT NOT NULL DEFAULT 0,
|
|
125
|
+
next_retry_at TIMESTAMPTZ DEFAULT NOW(),
|
|
126
|
+
last_error TEXT,
|
|
127
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
128
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
129
|
+
);
|
|
130
|
+
CREATE INDEX IF NOT EXISTS idx_write_jobs_claim ON memory_write_jobs(status, next_retry_at)
|
|
131
|
+
WHERE status IN ('pending', 'failed');
|
|
132
|
+
CREATE INDEX IF NOT EXISTS idx_write_jobs_memory ON memory_write_jobs(memory_id);
|
|
100
133
|
|
|
101
134
|
-- Memory fragments: granular vector decomposition for precision retrieval
|
|
102
135
|
-- Each memory is split into semantic fragments (summary, content chunks, tag context)
|
|
@@ -110,6 +143,37 @@ CREATE TABLE IF NOT EXISTS memory_fragments (
|
|
|
110
143
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
111
144
|
);
|
|
112
145
|
|
|
146
|
+
-- ============================================================
|
|
147
|
+
-- ENCRYPTION (PMP memory encryption-at-rest — see migration 021,
|
|
148
|
+
-- docs/pmp/memory-encryption-design.md §9). Owner-held envelope encryption.
|
|
149
|
+
-- ============================================================
|
|
150
|
+
|
|
151
|
+
-- Owner public-key registry. No private keys, ever.
|
|
152
|
+
CREATE TABLE IF NOT EXISTS encryption_keys (
|
|
153
|
+
owner_wallet TEXT PRIMARY KEY,
|
|
154
|
+
x25519_pubkey TEXT NOT NULL,
|
|
155
|
+
verifier_ct TEXT NOT NULL, -- secretbox("clude-key-verifier-v1") under derived key (H2)
|
|
156
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
157
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
-- Per-memory wrapped DEKs. Wrap = sealed box; wrap_pubkey is the ephemeral sender pubkey.
|
|
161
|
+
CREATE TABLE IF NOT EXISTS memory_dek_wraps (
|
|
162
|
+
memory_id BIGINT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
163
|
+
recipient TEXT NOT NULL, -- 'owner' | 'provider' | 'title_holder'
|
|
164
|
+
wrapped_dek TEXT NOT NULL, -- base64(nonce || box(DEK))
|
|
165
|
+
wrap_pubkey TEXT NOT NULL, -- base64 ephemeral sender X25519 pubkey
|
|
166
|
+
holder_wallet TEXT, -- (034) names the title_holder; NULL for owner/provider
|
|
167
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
168
|
+
CONSTRAINT memory_dek_wraps_recipient_chk CHECK (recipient IN ('owner', 'provider', 'title_holder')),
|
|
169
|
+
CONSTRAINT memory_dek_wraps_holder_chk CHECK ((recipient = 'title_holder') = (holder_wallet IS NOT NULL))
|
|
170
|
+
);
|
|
171
|
+
-- (036) holder-aware uniqueness: one owner + one provider per memory (NULLS NOT DISTINCT), and one
|
|
172
|
+
-- title_holder per (memory, holder) so a title sale's seller + buyer wraps coexist (RT7 additive).
|
|
173
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_dek_wraps_identity
|
|
174
|
+
ON memory_dek_wraps (memory_id, recipient, holder_wallet) NULLS NOT DISTINCT;
|
|
175
|
+
CREATE INDEX IF NOT EXISTS idx_dek_wraps_memory ON memory_dek_wraps(memory_id);
|
|
176
|
+
|
|
113
177
|
-- Dream logs: consolidation, reflection, emergence sessions
|
|
114
178
|
CREATE TABLE IF NOT EXISTS dream_logs (
|
|
115
179
|
id BIGSERIAL PRIMARY KEY,
|
|
@@ -133,6 +197,8 @@ CREATE INDEX IF NOT EXISTS idx_memories_evidence ON memories USING GIN(evidence_
|
|
|
133
197
|
CREATE INDEX IF NOT EXISTS idx_memories_owner ON memories(owner_wallet);
|
|
134
198
|
CREATE INDEX IF NOT EXISTS idx_memories_event_date ON memories(event_date) WHERE event_date IS NOT NULL;
|
|
135
199
|
CREATE INDEX IF NOT EXISTS idx_memories_ts_summary ON memories USING GIN (ts_summary);
|
|
200
|
+
CREATE INDEX IF NOT EXISTS idx_memories_content_tokens ON memories USING GIN (content_tokens);
|
|
201
|
+
CREATE INDEX IF NOT EXISTS idx_memories_delegated ON memories(provider_delegated) WHERE encrypted = TRUE;
|
|
136
202
|
|
|
137
203
|
-- Vector similarity indexes (HNSW for fast approximate nearest neighbor)
|
|
138
204
|
CREATE INDEX IF NOT EXISTS idx_memories_embedding ON memories USING hnsw (embedding vector_cosine_ops);
|
|
@@ -168,7 +234,11 @@ BEGIN
|
|
|
168
234
|
AND m.decay_factor >= min_decay
|
|
169
235
|
AND (filter_types IS NULL OR m.memory_type = ANY(filter_types))
|
|
170
236
|
AND (filter_user IS NULL OR m.related_user = filter_user)
|
|
171
|
-
AND (
|
|
237
|
+
AND (
|
|
238
|
+
filter_owner IS NULL
|
|
239
|
+
OR (filter_owner = '__BOT_OWN__' AND m.owner_wallet IS NULL)
|
|
240
|
+
OR m.owner_wallet = filter_owner
|
|
241
|
+
)
|
|
172
242
|
AND (filter_tags IS NULL OR m.tags && filter_tags)
|
|
173
243
|
AND (1 - (m.embedding <=> query_embedding)) > match_threshold
|
|
174
244
|
ORDER BY m.embedding <=> query_embedding
|
|
@@ -201,7 +271,11 @@ BEGIN
|
|
|
201
271
|
AND m.decay_factor >= min_decay
|
|
202
272
|
AND (filter_types IS NULL OR m.memory_type = ANY(filter_types))
|
|
203
273
|
AND (filter_user IS NULL OR m.related_user = filter_user)
|
|
204
|
-
AND (
|
|
274
|
+
AND (
|
|
275
|
+
filter_owner IS NULL
|
|
276
|
+
OR (filter_owner = '__BOT_OWN__' AND m.owner_wallet IS NULL)
|
|
277
|
+
OR m.owner_wallet = filter_owner
|
|
278
|
+
)
|
|
205
279
|
AND (filter_tags IS NULL OR m.tags && filter_tags)
|
|
206
280
|
AND (1 - (m.embedding <=> query_embedding)) > match_threshold
|
|
207
281
|
AND (start_date IS NULL OR COALESCE(m.event_date, m.created_at) >= start_date)
|
|
@@ -213,6 +287,66 @@ $$;
|
|
|
213
287
|
|
|
214
288
|
-- BM25-ranked full-text search using tsvector/tsquery (Exp 8)
|
|
215
289
|
-- Replaces ilike-based keyword search with stemming and TF-IDF ranking.
|
|
290
|
+
-- Populate content_tokens from a transient plaintext arg (PostgREST can't express to_tsvector inline).
|
|
291
|
+
-- setweight 'B' mirrors the old combined ts_summary weighting (summary 'A' > content 'B').
|
|
292
|
+
CREATE OR REPLACE FUNCTION set_memory_content_tokens(p_memory_id bigint, p_text text)
|
|
293
|
+
RETURNS void LANGUAGE sql AS $$
|
|
294
|
+
UPDATE memories
|
|
295
|
+
SET content_tokens = CASE
|
|
296
|
+
WHEN p_text IS NULL OR p_text = '' THEN NULL
|
|
297
|
+
ELSE setweight(to_tsvector('english', p_text), 'B')
|
|
298
|
+
END
|
|
299
|
+
WHERE id = p_memory_id;
|
|
300
|
+
$$;
|
|
301
|
+
|
|
302
|
+
-- Atomic revoke: clear plaintext + drop the provider wrap in one transaction (encryption §7).
|
|
303
|
+
CREATE OR REPLACE FUNCTION revoke_memory(p_memory_id bigint, p_summary_ct text, p_embedding_ct text)
|
|
304
|
+
RETURNS void LANGUAGE plpgsql AS $$
|
|
305
|
+
BEGIN
|
|
306
|
+
UPDATE memories SET
|
|
307
|
+
summary = '',
|
|
308
|
+
summary_ciphertext = p_summary_ct,
|
|
309
|
+
embedding = NULL,
|
|
310
|
+
embedding_ciphertext = NULLIF(p_embedding_ct, ''),
|
|
311
|
+
content_tokens = NULL,
|
|
312
|
+
provider_delegated = false
|
|
313
|
+
WHERE id = p_memory_id;
|
|
314
|
+
DELETE FROM memory_dek_wraps WHERE memory_id = p_memory_id AND recipient = 'provider';
|
|
315
|
+
-- Fragment parity (migration 043): fragments hold plaintext + live embeddings,
|
|
316
|
+
-- which kept revoked memories findable through the fragment lane.
|
|
317
|
+
DELETE FROM memory_fragments WHERE memory_id = p_memory_id;
|
|
318
|
+
END;
|
|
319
|
+
$$;
|
|
320
|
+
|
|
321
|
+
-- Atomic re-delegate (encryption §7) — inverse of revoke_memory. Restores plaintext
|
|
322
|
+
-- summary/embedding, rebuilds content_tokens via the canonical builder, clears ciphertext
|
|
323
|
+
-- cols, sets provider_delegated=true, (re-)inserts the provider wrap. Caller passes decrypted
|
|
324
|
+
-- plaintext (it holds the validated DEK); plaintext is transient, not stored beyond columns.
|
|
325
|
+
CREATE OR REPLACE FUNCTION redelegate_memory(
|
|
326
|
+
p_memory_id bigint,
|
|
327
|
+
p_summary text,
|
|
328
|
+
p_embedding text,
|
|
329
|
+
p_content text,
|
|
330
|
+
p_wrapped_dek text,
|
|
331
|
+
p_wrap_pubkey text
|
|
332
|
+
)
|
|
333
|
+
RETURNS void LANGUAGE plpgsql AS $$
|
|
334
|
+
BEGIN
|
|
335
|
+
UPDATE memories SET
|
|
336
|
+
summary = p_summary,
|
|
337
|
+
summary_ciphertext = NULL,
|
|
338
|
+
embedding = NULLIF(p_embedding, '')::vector,
|
|
339
|
+
embedding_ciphertext = NULL,
|
|
340
|
+
provider_delegated = true
|
|
341
|
+
WHERE id = p_memory_id;
|
|
342
|
+
PERFORM set_memory_content_tokens(p_memory_id, p_content);
|
|
343
|
+
INSERT INTO memory_dek_wraps (memory_id, recipient, wrapped_dek, wrap_pubkey)
|
|
344
|
+
VALUES (p_memory_id, 'provider', p_wrapped_dek, p_wrap_pubkey)
|
|
345
|
+
ON CONFLICT (memory_id, recipient) DO UPDATE
|
|
346
|
+
SET wrapped_dek = EXCLUDED.wrapped_dek, wrap_pubkey = EXCLUDED.wrap_pubkey;
|
|
347
|
+
END;
|
|
348
|
+
$$;
|
|
349
|
+
|
|
216
350
|
CREATE OR REPLACE FUNCTION bm25_search_memories(
|
|
217
351
|
search_query text,
|
|
218
352
|
match_count int DEFAULT 20,
|
|
@@ -231,11 +365,17 @@ BEGIN
|
|
|
231
365
|
RETURN;
|
|
232
366
|
END IF;
|
|
233
367
|
RETURN QUERY
|
|
234
|
-
SELECT m.id,
|
|
368
|
+
SELECT m.id,
|
|
369
|
+
(ts_rank_cd(COALESCE(m.ts_summary, ''::tsvector), tsquery_val, 32)
|
|
370
|
+
+ ts_rank_cd(COALESCE(m.content_tokens, ''::tsvector), tsquery_val, 32))::float AS rank
|
|
235
371
|
FROM memories m
|
|
236
|
-
WHERE m.ts_summary @@ tsquery_val
|
|
372
|
+
WHERE (m.ts_summary @@ tsquery_val OR m.content_tokens @@ tsquery_val)
|
|
237
373
|
AND m.decay_factor >= min_decay
|
|
238
|
-
AND (
|
|
374
|
+
AND (
|
|
375
|
+
filter_owner IS NULL
|
|
376
|
+
OR (filter_owner = '__BOT_OWN__' AND m.owner_wallet IS NULL)
|
|
377
|
+
OR m.owner_wallet = filter_owner
|
|
378
|
+
)
|
|
239
379
|
AND (filter_types IS NULL OR m.memory_type = ANY(filter_types))
|
|
240
380
|
AND (filter_tags IS NULL OR m.tags && filter_tags)
|
|
241
381
|
ORDER BY rank DESC
|
|
@@ -262,6 +402,7 @@ CREATE TABLE IF NOT EXISTS memory_links (
|
|
|
262
402
|
'follows', -- temporal sequence
|
|
263
403
|
'relates', -- general semantic association
|
|
264
404
|
'resolves', -- contradiction resolution outcome
|
|
405
|
+
'supersedes', -- decisive replacement: new fact overrides an older one (Memory 3.0 C1, migration 044)
|
|
265
406
|
'happens_before', -- temporal ordering
|
|
266
407
|
'happens_after', -- temporal ordering
|
|
267
408
|
'concurrent_with' -- temporal co-occurrence
|
|
@@ -300,7 +441,11 @@ LANGUAGE sql AS $$
|
|
|
300
441
|
WHERE ml.source_id = ANY(seed_ids)
|
|
301
442
|
AND ml.target_id != ALL(seed_ids)
|
|
302
443
|
AND ml.strength >= min_strength
|
|
303
|
-
AND (
|
|
444
|
+
AND (
|
|
445
|
+
filter_owner IS NULL
|
|
446
|
+
OR (filter_owner = '__BOT_OWN__' AND m.owner_wallet IS NULL)
|
|
447
|
+
OR m.owner_wallet = filter_owner
|
|
448
|
+
)
|
|
304
449
|
UNION
|
|
305
450
|
SELECT DISTINCT ON (ml.source_id, ml.link_type)
|
|
306
451
|
ml.source_id AS memory_id,
|
|
@@ -312,7 +457,11 @@ LANGUAGE sql AS $$
|
|
|
312
457
|
WHERE ml.target_id = ANY(seed_ids)
|
|
313
458
|
AND ml.source_id != ALL(seed_ids)
|
|
314
459
|
AND ml.strength >= min_strength
|
|
315
|
-
AND (
|
|
460
|
+
AND (
|
|
461
|
+
filter_owner IS NULL
|
|
462
|
+
OR (filter_owner = '__BOT_OWN__' AND m.owner_wallet IS NULL)
|
|
463
|
+
OR m.owner_wallet = filter_owner
|
|
464
|
+
)
|
|
316
465
|
ORDER BY strength DESC
|
|
317
466
|
LIMIT max_results;
|
|
318
467
|
$$;
|
|
@@ -411,7 +560,9 @@ CREATE OR REPLACE FUNCTION match_memory_fragments(
|
|
|
411
560
|
query_embedding vector(1024),
|
|
412
561
|
match_threshold float DEFAULT 0.3,
|
|
413
562
|
match_count int DEFAULT 10,
|
|
414
|
-
filter_owner text DEFAULT NULL
|
|
563
|
+
filter_owner text DEFAULT NULL,
|
|
564
|
+
min_decay float DEFAULT 0.0,
|
|
565
|
+
filter_types text[] DEFAULT NULL
|
|
415
566
|
)
|
|
416
567
|
RETURNS TABLE (memory_id bigint, max_similarity float)
|
|
417
568
|
LANGUAGE plpgsql AS $$
|
|
@@ -422,7 +573,13 @@ BEGIN
|
|
|
422
573
|
JOIN memories m ON m.id = f.memory_id
|
|
423
574
|
WHERE f.embedding IS NOT NULL
|
|
424
575
|
AND (1 - (f.embedding <=> query_embedding)) > match_threshold
|
|
425
|
-
AND
|
|
576
|
+
AND m.decay_factor >= min_decay
|
|
577
|
+
AND (filter_types IS NULL OR m.memory_type = ANY(filter_types))
|
|
578
|
+
AND (
|
|
579
|
+
filter_owner IS NULL
|
|
580
|
+
OR (filter_owner = '__BOT_OWN__' AND m.owner_wallet IS NULL)
|
|
581
|
+
OR m.owner_wallet = filter_owner
|
|
582
|
+
)
|
|
426
583
|
GROUP BY f.memory_id
|
|
427
584
|
ORDER BY max_similarity DESC
|
|
428
585
|
LIMIT match_count;
|
|
@@ -529,3 +686,110 @@ CREATE TABLE IF NOT EXISTS chat_usage (
|
|
|
529
686
|
);
|
|
530
687
|
|
|
531
688
|
CREATE INDEX IF NOT EXISTS idx_chat_usage_wallet ON chat_usage(wallet_address, created_at DESC);
|
|
689
|
+
|
|
690
|
+
-- ─────────── Wiki pack installations (PR #138) ───────────
|
|
691
|
+
-- Tracks which wiki packs (Workspace, Compliance, Sales, future third-party
|
|
692
|
+
-- packs) each wallet has installed. Drives the topic rail in /wiki and the
|
|
693
|
+
-- auto-categorisation rules applied to incoming memories.
|
|
694
|
+
|
|
695
|
+
CREATE TABLE IF NOT EXISTS wiki_pack_installations (
|
|
696
|
+
id BIGSERIAL PRIMARY KEY,
|
|
697
|
+
owner_wallet TEXT NOT NULL,
|
|
698
|
+
pack_id TEXT NOT NULL,
|
|
699
|
+
installed_at TIMESTAMPTZ DEFAULT NOW(),
|
|
700
|
+
UNIQUE (owner_wallet, pack_id)
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
CREATE INDEX IF NOT EXISTS idx_wiki_pack_installations_owner
|
|
704
|
+
ON wiki_pack_installations(owner_wallet);
|
|
705
|
+
|
|
706
|
+
-- ─────────── PMP tokenisation (migration 019) ───────────
|
|
707
|
+
-- Tokenisation columns on memories so each memory can carry a content hash
|
|
708
|
+
-- + compressed-NFT address on Solana. Content-bundle Pack registry and
|
|
709
|
+
-- Merkle-tree-aware join table for selective disclosure.
|
|
710
|
+
-- See packages/database/migrations/019_pmp_tokenisation.sql for full notes.
|
|
711
|
+
|
|
712
|
+
ALTER TABLE memories
|
|
713
|
+
ADD COLUMN IF NOT EXISTS content_hash TEXT,
|
|
714
|
+
ADD COLUMN IF NOT EXISTS cnft_address TEXT,
|
|
715
|
+
ADD COLUMN IF NOT EXISTS cnft_tree TEXT,
|
|
716
|
+
ADD COLUMN IF NOT EXISTS cnft_leaf_index BIGINT,
|
|
717
|
+
ADD COLUMN IF NOT EXISTS cnft_tx_sig TEXT,
|
|
718
|
+
ADD COLUMN IF NOT EXISTS tokenization_status TEXT
|
|
719
|
+
CHECK (tokenization_status IN ('pending', 'minted', 'skipped', 'failed')),
|
|
720
|
+
ADD COLUMN IF NOT EXISTS tokenized_at TIMESTAMPTZ;
|
|
721
|
+
|
|
722
|
+
CREATE INDEX IF NOT EXISTS idx_memories_content_hash
|
|
723
|
+
ON memories(content_hash) WHERE content_hash IS NOT NULL;
|
|
724
|
+
CREATE INDEX IF NOT EXISTS idx_memories_cnft_address
|
|
725
|
+
ON memories(cnft_address) WHERE cnft_address IS NOT NULL;
|
|
726
|
+
CREATE INDEX IF NOT EXISTS idx_memories_tok_status
|
|
727
|
+
ON memories(tokenization_status)
|
|
728
|
+
WHERE tokenization_status IN ('pending', 'failed');
|
|
729
|
+
|
|
730
|
+
CREATE TABLE IF NOT EXISTS cnft_trees (
|
|
731
|
+
tree_address TEXT PRIMARY KEY,
|
|
732
|
+
capacity INTEGER NOT NULL,
|
|
733
|
+
current_leaves INTEGER NOT NULL DEFAULT 0,
|
|
734
|
+
is_active BOOLEAN DEFAULT TRUE,
|
|
735
|
+
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
CREATE INDEX IF NOT EXISTS idx_cnft_trees_active
|
|
739
|
+
ON cnft_trees(is_active) WHERE is_active = TRUE;
|
|
740
|
+
|
|
741
|
+
CREATE TABLE IF NOT EXISTS memory_packs (
|
|
742
|
+
pack_id TEXT PRIMARY KEY,
|
|
743
|
+
manifest_id TEXT,
|
|
744
|
+
author_wallet TEXT NOT NULL,
|
|
745
|
+
name TEXT NOT NULL,
|
|
746
|
+
description TEXT,
|
|
747
|
+
version TEXT NOT NULL,
|
|
748
|
+
memory_count INTEGER NOT NULL,
|
|
749
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
750
|
+
published_at TIMESTAMPTZ,
|
|
751
|
+
merkle_root TEXT,
|
|
752
|
+
pack_token_address TEXT,
|
|
753
|
+
pack_token_tx_sig TEXT,
|
|
754
|
+
pack_schema_version SMALLINT DEFAULT 1,
|
|
755
|
+
gate_uri TEXT,
|
|
756
|
+
tokenized_at TIMESTAMPTZ
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
CREATE INDEX IF NOT EXISTS idx_memory_packs_author
|
|
760
|
+
ON memory_packs(author_wallet);
|
|
761
|
+
CREATE INDEX IF NOT EXISTS idx_memory_packs_published
|
|
762
|
+
ON memory_packs(published_at) WHERE published_at IS NOT NULL;
|
|
763
|
+
CREATE INDEX IF NOT EXISTS idx_memory_packs_token
|
|
764
|
+
ON memory_packs(pack_token_address) WHERE pack_token_address IS NOT NULL;
|
|
765
|
+
|
|
766
|
+
CREATE TABLE IF NOT EXISTS memory_pack_contents (
|
|
767
|
+
pack_id TEXT NOT NULL REFERENCES memory_packs(pack_id) ON DELETE CASCADE,
|
|
768
|
+
memory_id BIGINT NOT NULL REFERENCES memories(id) ON DELETE RESTRICT,
|
|
769
|
+
leaf_index INTEGER NOT NULL,
|
|
770
|
+
content_hash TEXT NOT NULL,
|
|
771
|
+
PRIMARY KEY (pack_id, memory_id),
|
|
772
|
+
UNIQUE (pack_id, leaf_index)
|
|
773
|
+
);
|
|
774
|
+
|
|
775
|
+
CREATE INDEX IF NOT EXISTS idx_memory_pack_contents_memory
|
|
776
|
+
ON memory_pack_contents(memory_id);
|
|
777
|
+
|
|
778
|
+
-- ─────────── PMP batch tokenisation (migration 020) ───────────
|
|
779
|
+
-- The backfill commits memories in batches: one Merkle root on-chain for
|
|
780
|
+
-- many memories. This table records each batch so a memory's inclusion
|
|
781
|
+
-- proof can be regenerated (memories.cnft_tree holds the batch merkle_root).
|
|
782
|
+
|
|
783
|
+
CREATE TABLE IF NOT EXISTS memory_batches (
|
|
784
|
+
batch_id TEXT PRIMARY KEY,
|
|
785
|
+
merkle_root TEXT NOT NULL,
|
|
786
|
+
memory_count INTEGER NOT NULL,
|
|
787
|
+
leaves JSONB NOT NULL,
|
|
788
|
+
commitment_asset TEXT,
|
|
789
|
+
commitment_tx_sig TEXT,
|
|
790
|
+
chain TEXT NOT NULL DEFAULT 'solana',
|
|
791
|
+
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
CREATE INDEX IF NOT EXISTS idx_memory_batches_root
|
|
795
|
+
ON memory_batches(merkle_root);
|