@relayfile/adapter-airtable 0.2.7 → 0.2.9

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.
@@ -0,0 +1,33 @@
1
+ export interface DigestWindow {
2
+ readonly from: string;
3
+ readonly to: string;
4
+ }
5
+ export interface DigestChangeEvent {
6
+ readonly id?: string;
7
+ readonly timestamp?: string;
8
+ readonly occurredAt?: string;
9
+ readonly eventType?: string;
10
+ readonly type?: string;
11
+ readonly action?: string;
12
+ readonly canonicalPath?: string;
13
+ readonly path?: string;
14
+ }
15
+ export interface DigestContext {
16
+ readonly provider: string;
17
+ readonly window: DigestWindow;
18
+ changeEvents(filter?: {
19
+ providers?: string[];
20
+ paths?: string[];
21
+ }): Promise<readonly DigestChangeEvent[]>;
22
+ }
23
+ export interface DigestBullet {
24
+ readonly text: string;
25
+ readonly canonicalPath: string;
26
+ }
27
+ export interface DigestSection {
28
+ readonly provider: string;
29
+ readonly bullets: readonly DigestBullet[];
30
+ }
31
+ export type DigestHandler = (ctx: DigestContext) => Promise<DigestSection | null>;
32
+ export declare const digest: DigestHandler;
33
+ //# sourceMappingURL=digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,YAAY,CAAC,MAAM,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;CAC3C;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;AAElF,eAAO,MAAM,MAAM,EAAE,aAepB,CAAC"}
package/dist/digest.js ADDED
@@ -0,0 +1,155 @@
1
+ export const digest = async (ctx) => {
2
+ const events = await ctx.changeEvents({ providers: [ctx.provider] });
3
+ const bullets = events
4
+ .filter(hasDigestPath)
5
+ .slice()
6
+ .sort(compareEvents)
7
+ .map((event) => {
8
+ const canonicalPath = normalizeDigestPath(digestEventPath(event));
9
+ return {
10
+ text: `${airtableIdentifier(canonicalPath)} ${pastTense(event)}`,
11
+ canonicalPath,
12
+ };
13
+ });
14
+ return bullets.length === 0 ? null : { provider: ctx.provider, bullets };
15
+ };
16
+ function hasDigestPath(event) {
17
+ return (typeof digestEventPath(event) === 'string'
18
+ && isCanonicalDigestPath(digestEventPath(event))
19
+ && (digestEventPath(event) === 'airtable' || digestEventPath(event) === '/airtable' || digestEventPath(event).startsWith('airtable/') || digestEventPath(event).startsWith('/airtable/')));
20
+ }
21
+ function isCanonicalDigestPath(path) {
22
+ const segments = normalizeDigestPath(path).split('/').filter(Boolean);
23
+ const leaf = segments.at(-1) ?? '';
24
+ return leaf !== 'LAYOUT.md'
25
+ && leaf !== '_index.json'
26
+ && !hasDigestAliasDirectory(segments);
27
+ }
28
+ const DIGEST_ALIAS_PROVIDER_SEGMENTS = new Set([
29
+ 'asana',
30
+ 'clickup',
31
+ 'confluence',
32
+ 'github',
33
+ 'gitlab',
34
+ 'jira',
35
+ 'linear',
36
+ 'notion',
37
+ 'slack',
38
+ ]);
39
+ const DIGEST_ALIAS_SEGMENTS = new Set([
40
+ 'by-assignee',
41
+ 'by-creator',
42
+ 'by-database',
43
+ 'by-id',
44
+ 'by-key',
45
+ 'by-name',
46
+ 'by-parent',
47
+ 'by-priority',
48
+ 'by-ref',
49
+ 'by-space',
50
+ 'by-state',
51
+ 'by-status',
52
+ 'by-title',
53
+ 'by-uuid',
54
+ ]);
55
+ const DIGEST_ALIAS_PARENT_SEGMENTS = new Set([
56
+ 'channels',
57
+ 'commits',
58
+ 'databases',
59
+ 'deployments',
60
+ 'issues',
61
+ 'pages',
62
+ 'pipelines',
63
+ 'projects',
64
+ 'pulls',
65
+ 'sprints',
66
+ 'spaces',
67
+ 'tags',
68
+ 'tasks',
69
+ 'teams',
70
+ 'users',
71
+ ]);
72
+ function hasDigestAliasDirectory(segments) {
73
+ const provider = segments[0] ?? '';
74
+ if (!DIGEST_ALIAS_PROVIDER_SEGMENTS.has(provider))
75
+ return false;
76
+ for (let index = 1; index < segments.length - 1; index += 1) {
77
+ const segment = segments[index];
78
+ const parent = segments[index - 1];
79
+ if (segment && parent && DIGEST_ALIAS_SEGMENTS.has(segment) && DIGEST_ALIAS_PARENT_SEGMENTS.has(parent)) {
80
+ return true;
81
+ }
82
+ }
83
+ return false;
84
+ }
85
+ function compareEvents(left, right) {
86
+ const leftMs = eventTimeMs(left);
87
+ const rightMs = eventTimeMs(right);
88
+ return (leftMs - rightMs
89
+ || (left.id ?? '').localeCompare(right.id ?? '')
90
+ || (digestEventPath(left) ?? '').localeCompare(digestEventPath(right) ?? ''));
91
+ }
92
+ function eventTime(event) {
93
+ return event.timestamp ?? event.occurredAt ?? '';
94
+ }
95
+ function eventTimeMs(event) {
96
+ const raw = eventTime(event);
97
+ if (!raw)
98
+ return Number.NEGATIVE_INFINITY;
99
+ const ms = Date.parse(raw);
100
+ return Number.isNaN(ms) ? Number.NEGATIVE_INFINITY : ms;
101
+ }
102
+ function digestEventPath(event) {
103
+ return event.canonicalPath ?? event.path ?? '';
104
+ }
105
+ function normalizeDigestPath(path) {
106
+ return path.replace(/^\/+/u, '');
107
+ }
108
+ function airtableIdentifier(path) {
109
+ const segments = path.split('/').filter(Boolean);
110
+ const segment = segments.at(-1) === 'meta.json' || segments.at(-1) === 'metadata.json'
111
+ ? segments.at(-2) ?? path
112
+ : segments.at(-1) ?? path;
113
+ const basename = segment.replace(/\.[^.]+$/u, '');
114
+ const separatorIndex = basename.lastIndexOf('__');
115
+ const id = separatorIndex > 0 ? basename.slice(0, separatorIndex) : basename;
116
+ if (path.includes('/records/'))
117
+ return `record ${id}`;
118
+ if (path.includes('/tables/'))
119
+ return `table ${id}`;
120
+ if (path.includes('/bases/'))
121
+ return `base ${id}`;
122
+ return id;
123
+ }
124
+ function pastTense(event) {
125
+ const action = (event.action ?? event.eventType ?? event.type ?? '').toLowerCase();
126
+ if (hasActionVerb(action, 'create|created|add|added|write|written')) {
127
+ return 'was created';
128
+ }
129
+ if (hasActionVerb(action, 'delete|deleted|remove|removed')) {
130
+ return 'was deleted';
131
+ }
132
+ if (hasActionVerb(action, 'archive|archived')) {
133
+ return 'was archived';
134
+ }
135
+ if (hasActionVerb(action, 'unarchive|unarchived|restore|restored')) {
136
+ return 'was unarchived';
137
+ }
138
+ if (hasActionVerb(action, 'complete|completed|done')) {
139
+ return 'was completed';
140
+ }
141
+ if (hasActionVerb(action, 'cancel|canceled|cancelled')) {
142
+ return 'was canceled';
143
+ }
144
+ if (hasActionVerb(action, 'resolve|resolved')) {
145
+ return 'was resolved';
146
+ }
147
+ if (hasActionVerb(action, 'merge|merged')) {
148
+ return 'was merged';
149
+ }
150
+ return 'was updated';
151
+ }
152
+ function hasActionVerb(action, verbs) {
153
+ return new RegExp(`(^|[^a-z0-9])(${verbs})([^a-z0-9]|$)`, 'u').test(action);
154
+ }
155
+ //# sourceMappingURL=digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.js","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=digest.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.test.d.ts","sourceRoot":"","sources":["../src/digest.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,108 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { digest } from './digest.js';
4
+ test('digest returns deterministic Airtable bullets sorted by event time and id', async () => {
5
+ const ctx = {
6
+ provider: 'airtable',
7
+ window: { from: '2026-05-12T00:00:00.000Z', to: '2026-05-13T00:00:00.000Z' },
8
+ async changeEvents(filter) {
9
+ assert.deepEqual(filter, { providers: ['airtable'] });
10
+ return [
11
+ {
12
+ id: 'evt-2',
13
+ timestamp: '2026-05-12T09:00:00.000Z',
14
+ action: 'deleted',
15
+ canonicalPath: '/airtable/bases/appXYZ/tables/tblABC/records/rec456__invoice.json',
16
+ },
17
+ {
18
+ id: 'evt-3',
19
+ timestamp: '2026-05-12T10:00:00.000Z',
20
+ action: 'updated',
21
+ canonicalPath: '/airtable/bases/appXYZ/tables/tblABC/records/rec789__status.json',
22
+ },
23
+ {
24
+ id: 'evt-1',
25
+ timestamp: '2026-05-12T08:00:00.000Z',
26
+ action: 'created',
27
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec123__contact.json',
28
+ },
29
+ ];
30
+ },
31
+ };
32
+ const first = await digest(ctx);
33
+ const second = await digest(ctx);
34
+ assert.deepEqual(first, second);
35
+ assert.deepEqual(first, {
36
+ provider: 'airtable',
37
+ bullets: [
38
+ {
39
+ text: 'record rec123 was created',
40
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec123__contact.json',
41
+ },
42
+ {
43
+ text: 'record rec456 was deleted',
44
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec456__invoice.json',
45
+ },
46
+ {
47
+ text: 'record rec789 was updated',
48
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec789__status.json',
49
+ },
50
+ ],
51
+ });
52
+ });
53
+ test('digest classifies Airtable terminal lifecycle actions explicitly', async () => {
54
+ const ctx = {
55
+ provider: 'airtable',
56
+ window: { from: '2026-05-12T00:00:00.000Z', to: '2026-05-13T00:00:00.000Z' },
57
+ async changeEvents() {
58
+ return [
59
+ {
60
+ id: 'evt-1',
61
+ timestamp: '2026-05-12T08:00:00.000Z',
62
+ action: 'archived',
63
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec999__old.json',
64
+ },
65
+ {
66
+ id: 'evt-2',
67
+ timestamp: '2026-05-12T09:00:00.000Z',
68
+ action: 'canceled',
69
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec998__void.json',
70
+ },
71
+ {
72
+ id: 'evt-3',
73
+ timestamp: '2026-05-12T10:00:00.000Z',
74
+ action: 'resolved',
75
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec997__ticket.json',
76
+ },
77
+ ];
78
+ },
79
+ };
80
+ assert.deepEqual(await digest(ctx), {
81
+ provider: 'airtable',
82
+ bullets: [
83
+ {
84
+ text: 'record rec999 was archived',
85
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec999__old.json',
86
+ },
87
+ {
88
+ text: 'record rec998 was canceled',
89
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec998__void.json',
90
+ },
91
+ {
92
+ text: 'record rec997 was resolved',
93
+ canonicalPath: 'airtable/bases/appXYZ/tables/tblABC/records/rec997__ticket.json',
94
+ },
95
+ ],
96
+ });
97
+ });
98
+ test('digest returns null for an empty Airtable event window', async () => {
99
+ const ctx = {
100
+ provider: 'airtable',
101
+ window: { from: '2026-05-12T00:00:00.000Z', to: '2026-05-13T00:00:00.000Z' },
102
+ async changeEvents() {
103
+ return [];
104
+ },
105
+ };
106
+ assert.equal(await digest(ctx), null);
107
+ });
108
+ //# sourceMappingURL=digest.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.test.js","sourceRoot":"","sources":["../src/digest.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './airtable-adapter.js';
2
+ export * from './digest.js';
2
3
  export * from './fetch-on-demand.js';
3
4
  export * from './path-mapper.js';
4
5
  export * from './queries.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './airtable-adapter.js';
2
+ export * from './digest.js';
2
3
  export * from './fetch-on-demand.js';
3
4
  export * from './path-mapper.js';
4
5
  export * from './queries.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relayfile/adapter-airtable",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Airtable adapter package for Relayfile",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",