@e-sig/supabase 0.1.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/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/audit-store.d.ts +16 -0
- package/dist/audit-store.d.ts.map +1 -0
- package/dist/audit-store.js +38 -0
- package/dist/audit-store.js.map +1 -0
- package/dist/cert-store.d.ts +24 -0
- package/dist/cert-store.d.ts.map +1 -0
- package/dist/cert-store.js +112 -0
- package/dist/cert-store.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/storage.d.ts +22 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +29 -0
- package/dist/storage.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Opendelphi contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @e-sig/supabase
|
|
2
|
+
|
|
3
|
+
Supabase reference adapters for [`@e-sig/core`](https://github.com/vmvtech/esig-suite/tree/main/packages/esig-core) —
|
|
4
|
+
self-contained PDF e-signature persistence on Supabase Postgres + Storage.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm i @e-sig/core @e-sig/supabase @supabase/supabase-js
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Apply `migrations/0001_esig_self_contained.sql` (in the suite root) first.
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { createClient } from "@supabase/supabase-js";
|
|
14
|
+
import {
|
|
15
|
+
SupabaseCertStore,
|
|
16
|
+
SupabaseAuditLogStore,
|
|
17
|
+
SupabasePdfStorageStore,
|
|
18
|
+
} from "@e-sig/supabase";
|
|
19
|
+
|
|
20
|
+
const service = createClient(url, serviceRoleKey); // service-role: bypasses RLS for cert/audit/storage writes
|
|
21
|
+
|
|
22
|
+
const certStore = new SupabaseCertStore(service); // table "org_signing_certs", tenant col "tenant_id"
|
|
23
|
+
const auditStore = new SupabaseAuditLogStore(service); // table "esig_audit_log"
|
|
24
|
+
const storage = new SupabasePdfStorageStore(service); // bucket "signed-documents"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
All three constructors take options to map onto an existing schema, e.g. the
|
|
28
|
+
Opendelphi schema keys on `org_id`:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
new SupabaseCertStore(service, { table: "org_signing_certs", tenantColumn: "org_id" });
|
|
32
|
+
new SupabaseAuditLogStore(service, { tenantColumn: "org_id" });
|
|
33
|
+
new SupabasePdfStorageStore(service, { bucket: "signed-documents" });
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Pass these to `signDocument()` from `@e-sig/core`. The stores handle the
|
|
37
|
+
Postgres `\x`-hex bytea round-trip for the encrypted key and return the storage
|
|
38
|
+
**path** (private buckets have no public URL — serve via an RLS-gated download route).
|
|
39
|
+
|
|
40
|
+
Peer deps: `@e-sig/core`, `@supabase/supabase-js`. License: MIT.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import type { AuditLogStore, AuditLogEntry, AuditLogRow } from "@e-sig/core";
|
|
3
|
+
export interface SupabaseAuditLogStoreOptions {
|
|
4
|
+
/** Table name. Default `esig_audit_log`. */
|
|
5
|
+
table?: string;
|
|
6
|
+
/** Tenant key column. Default `tenant_id`. */
|
|
7
|
+
tenantColumn?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class SupabaseAuditLogStore implements AuditLogStore {
|
|
10
|
+
private sb;
|
|
11
|
+
private table;
|
|
12
|
+
private tenantColumn;
|
|
13
|
+
constructor(sb: SupabaseClient, opts?: SupabaseAuditLogStoreOptions);
|
|
14
|
+
insert(entry: AuditLogEntry): Promise<AuditLogRow>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=audit-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-store.d.ts","sourceRoot":"","sources":["../src/audit-store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7E,MAAM,WAAW,4BAA4B;IAC3C,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,qBAAsB,YAAW,aAAa;IAG7C,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAS;gBACT,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE,4BAAiC;IAKzE,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;CAsBzD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @e-sig/supabase — SupabaseAuditLogStore
|
|
2
|
+
//
|
|
3
|
+
// Append-only AuditLogStore backed by a Postgres table (default `esig_audit_log`)
|
|
4
|
+
// via supabase-js. Tenant key column defaults to `tenant_id` (Opendelphi: `org_id`).
|
|
5
|
+
export class SupabaseAuditLogStore {
|
|
6
|
+
sb;
|
|
7
|
+
table;
|
|
8
|
+
tenantColumn;
|
|
9
|
+
constructor(sb, opts = {}) {
|
|
10
|
+
this.sb = sb;
|
|
11
|
+
this.table = opts.table ?? "esig_audit_log";
|
|
12
|
+
this.tenantColumn = opts.tenantColumn ?? "tenant_id";
|
|
13
|
+
}
|
|
14
|
+
async insert(entry) {
|
|
15
|
+
const { data, error } = await this.sb
|
|
16
|
+
.from(this.table)
|
|
17
|
+
.insert({
|
|
18
|
+
[this.tenantColumn]: entry.tenantId,
|
|
19
|
+
actor_user_id: entry.actorUserId ?? null,
|
|
20
|
+
action: entry.action,
|
|
21
|
+
target_table: entry.targetTable ?? null,
|
|
22
|
+
target_id: entry.targetId ?? null,
|
|
23
|
+
cert_id: entry.certId ?? null,
|
|
24
|
+
cert_fingerprint: entry.certFingerprint ?? null,
|
|
25
|
+
ip: entry.ip ?? null,
|
|
26
|
+
user_agent: entry.userAgent ?? null,
|
|
27
|
+
session_id: entry.sessionId ?? null,
|
|
28
|
+
signed_pdf_url: entry.signedPdfUrl ?? null,
|
|
29
|
+
metadata: entry.metadata ?? {},
|
|
30
|
+
})
|
|
31
|
+
.select("id, created_at")
|
|
32
|
+
.single();
|
|
33
|
+
if (error || !data)
|
|
34
|
+
throw new Error(`SupabaseAuditLogStore.insert: ${error?.message}`);
|
|
35
|
+
return { id: data.id, createdAt: new Date(data.created_at) };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=audit-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-store.js","sourceRoot":"","sources":["../src/audit-store.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,kFAAkF;AAClF,qFAAqF;AAYrF,MAAM,OAAO,qBAAqB;IAGZ;IAFZ,KAAK,CAAS;IACd,YAAY,CAAS;IAC7B,YAAoB,EAAkB,EAAE,OAAqC,EAAE;QAA3D,OAAE,GAAF,EAAE,CAAgB;QACpC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,gBAAgB,CAAC;QAC5C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,WAAW,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAoB;QAC/B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE;aAClC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;aAChB,MAAM,CAAC;YACN,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,QAAQ;YACnC,aAAa,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;YACxC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,YAAY,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;YACvC,SAAS,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;YACjC,OAAO,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;YAC7B,gBAAgB,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI;YAC/C,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,IAAI;YACpB,UAAU,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;YACnC,UAAU,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;YACnC,cAAc,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;YAC1C,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;SAC/B,CAAC;aACD,MAAM,CAAC,gBAAgB,CAAC;aACxB,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAY,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,UAAoB,CAAC,EAAE,CAAC;IACnF,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import type { CertStore, StoredCert, GeneratedCert } from "@e-sig/core";
|
|
3
|
+
export interface SupabaseCertStoreOptions {
|
|
4
|
+
/** Table name. Default `org_signing_certs`. */
|
|
5
|
+
table?: string;
|
|
6
|
+
/** Tenant key column. Default `tenant_id`. */
|
|
7
|
+
tenantColumn?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class SupabaseCertStore implements CertStore {
|
|
10
|
+
private sb;
|
|
11
|
+
private table;
|
|
12
|
+
private tenantColumn;
|
|
13
|
+
constructor(sb: SupabaseClient, opts?: SupabaseCertStoreOptions);
|
|
14
|
+
findActive(tenantId: string): Promise<StoredCert | null>;
|
|
15
|
+
insert(input: {
|
|
16
|
+
tenantId: string;
|
|
17
|
+
generated: GeneratedCert;
|
|
18
|
+
keyPemEncrypted: Uint8Array;
|
|
19
|
+
rotatedFromId?: string | null;
|
|
20
|
+
}): Promise<StoredCert>;
|
|
21
|
+
deactivate(id: string): Promise<void>;
|
|
22
|
+
findExpiring(withinDays: number): Promise<StoredCert[]>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=cert-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-store.d.ts","sourceRoot":"","sources":["../src/cert-store.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBxE,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA2CD,qBAAa,iBAAkB,YAAW,SAAS;IAGrC,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAS;gBACT,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE,wBAA6B;IAKrE,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAWxD,MAAM,CAAC,KAAK,EAAE;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,aAAa,CAAC;QACzB,eAAe,EAAE,UAAU,CAAC;QAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,GAAG,OAAO,CAAC,UAAU,CAAC;IAwBjB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAU9D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// @e-sig/supabase — SupabaseCertStore
|
|
2
|
+
//
|
|
3
|
+
// CertStore backed by a Postgres table (default `org_signing_certs`) via
|
|
4
|
+
// supabase-js. Matches the schema in migrations/0001_esig_self_contained.sql.
|
|
5
|
+
// The tenant key column is `tenant_id` in the bundled migration; pass
|
|
6
|
+
// `tenantColumn` if yours differs (Opendelphi uses `org_id`).
|
|
7
|
+
function toStoredCert(r, tenantColumn) {
|
|
8
|
+
// Postgres bytea comes back from PostgREST as a `\x<hex>` string. Decode to
|
|
9
|
+
// bytes. Legacy rows may be JSON-Buffer-wrapped (`{"type":"Buffer",...}`) by
|
|
10
|
+
// older supabase-js; detect + unwrap so they're at least diagnosable (they'll
|
|
11
|
+
// still fail GCM decryption — rotate to recover).
|
|
12
|
+
let keyBytes;
|
|
13
|
+
const raw = r.key_pem_encrypted;
|
|
14
|
+
if (raw instanceof Uint8Array) {
|
|
15
|
+
keyBytes = raw;
|
|
16
|
+
}
|
|
17
|
+
else if (typeof raw === "string" && raw.startsWith("\\x")) {
|
|
18
|
+
keyBytes = Buffer.from(raw.slice(2), "hex");
|
|
19
|
+
if (keyBytes.length > 0 && keyBytes[0] === 0x7b /* '{' */) {
|
|
20
|
+
try {
|
|
21
|
+
const parsed = JSON.parse(Buffer.from(keyBytes).toString("utf8"));
|
|
22
|
+
if (parsed && parsed.type === "Buffer" && Array.isArray(parsed.data)) {
|
|
23
|
+
keyBytes = Buffer.from(parsed.data);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
/* not JSON — keep original bytes */
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (typeof raw === "string") {
|
|
32
|
+
keyBytes = Buffer.from(raw, "base64");
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
keyBytes = new Uint8Array();
|
|
36
|
+
}
|
|
37
|
+
const tenantId = r[tenantColumn] ?? r.tenant_id ?? r.org_id ?? "";
|
|
38
|
+
return {
|
|
39
|
+
id: r.id,
|
|
40
|
+
tenantId,
|
|
41
|
+
certPem: r.cert_pem,
|
|
42
|
+
keyPemEncrypted: keyBytes,
|
|
43
|
+
certFingerprint: r.cert_fingerprint,
|
|
44
|
+
notBefore: new Date(r.not_before),
|
|
45
|
+
notAfter: new Date(r.not_after),
|
|
46
|
+
active: r.active,
|
|
47
|
+
rotatedFromId: r.rotated_from,
|
|
48
|
+
createdAt: new Date(r.created_at),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export class SupabaseCertStore {
|
|
52
|
+
sb;
|
|
53
|
+
table;
|
|
54
|
+
tenantColumn;
|
|
55
|
+
constructor(sb, opts = {}) {
|
|
56
|
+
this.sb = sb;
|
|
57
|
+
this.table = opts.table ?? "org_signing_certs";
|
|
58
|
+
this.tenantColumn = opts.tenantColumn ?? "tenant_id";
|
|
59
|
+
}
|
|
60
|
+
async findActive(tenantId) {
|
|
61
|
+
const { data, error } = await this.sb
|
|
62
|
+
.from(this.table)
|
|
63
|
+
.select("*")
|
|
64
|
+
.eq(this.tenantColumn, tenantId)
|
|
65
|
+
.eq("active", true)
|
|
66
|
+
.maybeSingle();
|
|
67
|
+
if (error)
|
|
68
|
+
throw new Error(`SupabaseCertStore.findActive: ${error.message}`);
|
|
69
|
+
return data ? toStoredCert(data, this.tenantColumn) : null;
|
|
70
|
+
}
|
|
71
|
+
async insert(input) {
|
|
72
|
+
// bytea wire encoding: supabase-js JSON-stringifies a Uint8Array, mangling
|
|
73
|
+
// the round-trip. Pre-encode as the Postgres bytea-in hex form `\x<hex>`.
|
|
74
|
+
const bytes = Buffer.isBuffer(input.keyPemEncrypted)
|
|
75
|
+
? input.keyPemEncrypted
|
|
76
|
+
: Buffer.from(input.keyPemEncrypted);
|
|
77
|
+
const hexEncoded = "\\x" + bytes.toString("hex");
|
|
78
|
+
const { data, error } = await this.sb
|
|
79
|
+
.from(this.table)
|
|
80
|
+
.insert({
|
|
81
|
+
[this.tenantColumn]: input.tenantId,
|
|
82
|
+
cert_pem: input.generated.certPem,
|
|
83
|
+
key_pem_encrypted: hexEncoded,
|
|
84
|
+
cert_fingerprint: input.generated.fingerprint,
|
|
85
|
+
not_before: input.generated.notBefore.toISOString(),
|
|
86
|
+
not_after: input.generated.notAfter.toISOString(),
|
|
87
|
+
rotated_from: input.rotatedFromId ?? null,
|
|
88
|
+
})
|
|
89
|
+
.select()
|
|
90
|
+
.single();
|
|
91
|
+
if (error || !data)
|
|
92
|
+
throw new Error(`SupabaseCertStore.insert: ${error?.message}`);
|
|
93
|
+
return toStoredCert(data, this.tenantColumn);
|
|
94
|
+
}
|
|
95
|
+
async deactivate(id) {
|
|
96
|
+
const { error } = await this.sb.from(this.table).update({ active: false }).eq("id", id);
|
|
97
|
+
if (error)
|
|
98
|
+
throw new Error(`SupabaseCertStore.deactivate: ${error.message}`);
|
|
99
|
+
}
|
|
100
|
+
async findExpiring(withinDays) {
|
|
101
|
+
const horizon = new Date(Date.now() + withinDays * 86400_000).toISOString();
|
|
102
|
+
const { data, error } = await this.sb
|
|
103
|
+
.from(this.table)
|
|
104
|
+
.select("*")
|
|
105
|
+
.eq("active", true)
|
|
106
|
+
.lte("not_after", horizon);
|
|
107
|
+
if (error)
|
|
108
|
+
throw new Error(`SupabaseCertStore.findExpiring: ${error.message}`);
|
|
109
|
+
return (data ?? []).map((r) => toStoredCert(r, this.tenantColumn));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=cert-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-store.js","sourceRoot":"","sources":["../src/cert-store.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SupabaseCertStore, type SupabaseCertStoreOptions, } from "./cert-store.js";
|
|
2
|
+
export { SupabaseAuditLogStore, type SupabaseAuditLogStoreOptions, } from "./audit-store.js";
|
|
3
|
+
export { SupabasePdfStorageStore, type SupabasePdfStorageStoreOptions, } from "./storage.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,EACvB,KAAK,8BAA8B,GACpC,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @e-sig/supabase
|
|
2
|
+
//
|
|
3
|
+
// Supabase reference implementations of the @e-sig/core persistence
|
|
4
|
+
// interfaces (CertStore, AuditLogStore, PdfStorageStore). Pair with the bundled
|
|
5
|
+
// migration (migrations/0001_esig_self_contained.sql). Table/bucket/tenant-column
|
|
6
|
+
// names are configurable so you can map onto your existing schema.
|
|
7
|
+
export { SupabaseCertStore, } from "./cert-store.js";
|
|
8
|
+
export { SupabaseAuditLogStore, } from "./audit-store.js";
|
|
9
|
+
export { SupabasePdfStorageStore, } from "./storage.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAClB,EAAE;AACF,oEAAoE;AACpE,gFAAgF;AAChF,kFAAkF;AAClF,mEAAmE;AAEnE,OAAO,EACL,iBAAiB,GAElB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,qBAAqB,GAEtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,GAExB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import type { PdfStorageStore } from "@e-sig/core";
|
|
3
|
+
export interface SupabasePdfStorageStoreOptions {
|
|
4
|
+
/** Bucket name. Default `signed-documents`. */
|
|
5
|
+
bucket?: string;
|
|
6
|
+
/** Allow overwriting an existing object at the path. Default false. */
|
|
7
|
+
upsert?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class SupabasePdfStorageStore implements PdfStorageStore {
|
|
10
|
+
private sb;
|
|
11
|
+
private bucket;
|
|
12
|
+
private upsert;
|
|
13
|
+
constructor(sb: SupabaseClient, opts?: SupabasePdfStorageStoreOptions);
|
|
14
|
+
upload(input: {
|
|
15
|
+
path: string;
|
|
16
|
+
bytes: Uint8Array;
|
|
17
|
+
contentType: string;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
url: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,8BAA8B;IAC7C,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,uBAAwB,YAAW,eAAe;IAGjD,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAU;gBACJ,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE,8BAAmC;IAK3E,MAAM,CAAC,KAAK,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,UAAU,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAU7B"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @e-sig/supabase — SupabasePdfStorageStore
|
|
2
|
+
//
|
|
3
|
+
// PdfStorageStore backed by a private Supabase Storage bucket (default
|
|
4
|
+
// `signed-documents`). Returns the storage PATH as the `url` — private buckets
|
|
5
|
+
// have no public URL, so serve signed PDFs through an auth-gated download route
|
|
6
|
+
// (RLS on the bucket restricts reads to the owning tenant). Uploads use the
|
|
7
|
+
// service-role client (bucket write policy is service-role-only).
|
|
8
|
+
export class SupabasePdfStorageStore {
|
|
9
|
+
sb;
|
|
10
|
+
bucket;
|
|
11
|
+
upsert;
|
|
12
|
+
constructor(sb, opts = {}) {
|
|
13
|
+
this.sb = sb;
|
|
14
|
+
this.bucket = opts.bucket ?? "signed-documents";
|
|
15
|
+
this.upsert = opts.upsert ?? false;
|
|
16
|
+
}
|
|
17
|
+
async upload(input) {
|
|
18
|
+
const body = Buffer.isBuffer(input.bytes) ? input.bytes : Buffer.from(input.bytes);
|
|
19
|
+
const { error } = await this.sb.storage.from(this.bucket).upload(input.path, body, {
|
|
20
|
+
contentType: input.contentType,
|
|
21
|
+
upsert: this.upsert,
|
|
22
|
+
});
|
|
23
|
+
if (error)
|
|
24
|
+
throw new Error(`SupabasePdfStorageStore.upload(${input.path}): ${error.message}`);
|
|
25
|
+
// Private bucket → return the path key; the app serves it via a download route.
|
|
26
|
+
return { url: input.path };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,uEAAuE;AACvE,+EAA+E;AAC/E,gFAAgF;AAChF,4EAA4E;AAC5E,kEAAkE;AAYlE,MAAM,OAAO,uBAAuB;IAGd;IAFZ,MAAM,CAAS;IACf,MAAM,CAAU;IACxB,YAAoB,EAAkB,EAAE,OAAuC,EAAE;QAA7D,OAAE,GAAF,EAAE,CAAgB;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,kBAAkB,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAIZ;QACC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnF,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE;YACjF,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,IAAI,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9F,gFAAgF;QAChF,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@e-sig/supabase",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Supabase adapters (CertStore / AuditLogStore / PdfStorageStore) for @e-sig/core — self-contained PDF e-signature persistence on Supabase Postgres + Storage.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.build.json",
|
|
24
|
+
"clean": "rm -rf dist",
|
|
25
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"supabase",
|
|
32
|
+
"pdf",
|
|
33
|
+
"esignature",
|
|
34
|
+
"pkcs7",
|
|
35
|
+
"self-contained",
|
|
36
|
+
"esign",
|
|
37
|
+
"certstore",
|
|
38
|
+
"audit-log"
|
|
39
|
+
],
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/vmvtech/esig-suite.git",
|
|
43
|
+
"directory": "packages/esig-supabase"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/vmvtech/esig-suite/tree/main/packages/esig-supabase#readme",
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@supabase/supabase-js": ">=2",
|
|
48
|
+
"@e-sig/core": "^0.4.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@supabase/supabase-js": "^2.98.0",
|
|
52
|
+
"@types/node": "^22.0.0",
|
|
53
|
+
"@e-sig/core": "^0.4.0",
|
|
54
|
+
"typescript": "^5.4.0"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"registry": "https://registry.npmjs.org",
|
|
58
|
+
"access": "public"
|
|
59
|
+
}
|
|
60
|
+
}
|