@memberjunction/connector-sharepoint 1.0.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/SharePointConnector.d.ts +191 -0
- package/dist/SharePointConnector.js +722 -0
- package/dist/SharePointConnector.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { type UserInfo } from '@memberjunction/core';
|
|
2
|
+
import type { MJCompanyIntegrationEntity, MJIntegrationObjectEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import { BaseRESTIntegrationConnector, type RESTAuthContext, type RESTResponse, type PaginationState, type PaginationType, type ConnectionTestResult, type ExternalObjectSchema, type ExternalFieldSchema, type FetchContext, type FetchBatchResult, type DefaultFieldMapping, type DefaultIntegrationConfig, type CreateRecordContext, type CRUDResult } from '@memberjunction/integration-engine';
|
|
4
|
+
/**
|
|
5
|
+
* Connection configuration parsed from CompanyIntegration credentials.
|
|
6
|
+
* SharePoint is accessed through Microsoft Graph v1.0 using Azure AD
|
|
7
|
+
* client-credentials (app-only) authentication.
|
|
8
|
+
*/
|
|
9
|
+
export interface SharePointConnectionConfig {
|
|
10
|
+
/** Azure AD tenant GUID */
|
|
11
|
+
TenantId: string;
|
|
12
|
+
/** App (client) registration GUID */
|
|
13
|
+
ClientId: string;
|
|
14
|
+
/** App client secret */
|
|
15
|
+
ClientSecret: string;
|
|
16
|
+
/** Optional override for the Graph base URL. Default: https://graph.microsoft.com/v1.0 */
|
|
17
|
+
GraphBaseUrl?: string;
|
|
18
|
+
/** OAuth scope. Default: https://graph.microsoft.com/.default */
|
|
19
|
+
Scope?: string;
|
|
20
|
+
/** Optional override for the Azure AD authority host. Default: https://login.microsoftonline.com.
|
|
21
|
+
* Set for sovereign clouds — Azure Government (https://login.microsoftonline.us), Azure China
|
|
22
|
+
* (https://login.chinacloudapi.cn). Mirrors DynamicsDataverseConnector.AuthorityHost. */
|
|
23
|
+
AuthorityHost?: string;
|
|
24
|
+
/** Maximum retries for rate-limited or failed requests. Default: 5 */
|
|
25
|
+
MaxRetries?: number;
|
|
26
|
+
/** HTTP request timeout in milliseconds. Default: 30000 */
|
|
27
|
+
RequestTimeoutMs?: number;
|
|
28
|
+
/** Minimum milliseconds between API requests. Default: 250 */
|
|
29
|
+
MinRequestIntervalMs?: number;
|
|
30
|
+
}
|
|
31
|
+
/** Extended auth context holding the Graph bearer token + config. */
|
|
32
|
+
interface SharePointAuthContext extends RESTAuthContext {
|
|
33
|
+
Config: SharePointConnectionConfig;
|
|
34
|
+
BaseUrl: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Connector for Microsoft SharePoint Online via Microsoft Graph v1.0.
|
|
38
|
+
*
|
|
39
|
+
* Extends BaseRESTIntegrationConnector — inherits pagination + template variable
|
|
40
|
+
* substitution from metadata. Template vars like `{id}` / `{siteId}` are resolved
|
|
41
|
+
* per-parent using IntegrationObject FK / PK metadata, so object hierarchies
|
|
42
|
+
* (sites -> lists -> list items) traverse automatically.
|
|
43
|
+
*
|
|
44
|
+
* Auth flow:
|
|
45
|
+
* 1. Client-credentials OAuth 2.0 against Azure AD
|
|
46
|
+
* 2. Bearer token attached to every Graph request
|
|
47
|
+
* 3. Token is refreshed proactively before expiry
|
|
48
|
+
*
|
|
49
|
+
* Pagination: `@odata.nextLink` cursor (per OData convention) — replayed verbatim.
|
|
50
|
+
*
|
|
51
|
+
* Incremental sync: Graph `/delta` for Site, DriveItem, and ListItem (the three
|
|
52
|
+
* objects the frozen contract proves carry `@odata.deltaLink`). The watermark is
|
|
53
|
+
* the full deltaLink URL, replayed verbatim; the first sync runs as a full fetch.
|
|
54
|
+
*
|
|
55
|
+
* Discovery is non-authoritative (DiscoveryIsAuthoritative inherits false): the 25
|
|
56
|
+
* standard objects come from Declared metadata; runtime field discovery only ADDS
|
|
57
|
+
* tenant-specific list columns. Absence in a refresh never deactivates.
|
|
58
|
+
*/
|
|
59
|
+
export declare class SharePointConnector extends BaseRESTIntegrationConnector {
|
|
60
|
+
private cachedAuth;
|
|
61
|
+
private tokenExpiresAt;
|
|
62
|
+
private lastRequestTime;
|
|
63
|
+
/**
|
|
64
|
+
* Verbatim from the frozen contract's Integration.Name AND the baseline-seeded
|
|
65
|
+
* `__mj.Integration` row — both are exactly `'SharePoint'`. This is load-bearing:
|
|
66
|
+
* the three-way invariant `IntegrationName === MJ: Integrations.Name === @RegisterClass
|
|
67
|
+
* driver→ClassName` is how the engine binds this connector to its Integration row. A
|
|
68
|
+
* mismatch (e.g. 'SharePoint Online') means the engine never resolves the connector,
|
|
69
|
+
* no connection is created, and the live sync lands 0 rows. DO NOT change this string.
|
|
70
|
+
*/
|
|
71
|
+
get IntegrationName(): string;
|
|
72
|
+
GetDefaultConfiguration(): DefaultIntegrationConfig | null;
|
|
73
|
+
GetDefaultFieldMappings(objectName: string, _entityName: string): DefaultFieldMapping[];
|
|
74
|
+
/**
|
|
75
|
+
* Verifies the service principal can reach Graph by fetching the tenant's
|
|
76
|
+
* organization record. Forces a token refresh so credentials are validated.
|
|
77
|
+
*/
|
|
78
|
+
TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Returns the static IntegrationObject list. Discovery of per-site custom
|
|
81
|
+
* lists happens via the SiteLists IntegrationObject's FetchChanges loop, not
|
|
82
|
+
* here — this is a capability catalog, not a live enumeration.
|
|
83
|
+
*/
|
|
84
|
+
DiscoverObjects(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ExternalObjectSchema[]>;
|
|
85
|
+
/**
|
|
86
|
+
* Returns static field metadata from IntegrationEngineBase, plus — for
|
|
87
|
+
* SiteListItems — augments with live list-column discovery per list.
|
|
88
|
+
* Custom columns are marked via the IsReadOnly=false / isSealed=false
|
|
89
|
+
* Graph-reported flags; callers downstream can set IsCustom accordingly.
|
|
90
|
+
*/
|
|
91
|
+
DiscoverFields(companyIntegration: MJCompanyIntegrationEntity, objectName: string, contextUser: UserInfo): Promise<ExternalFieldSchema[]>;
|
|
92
|
+
/**
|
|
93
|
+
* Top-level FetchChanges delegates to BaseRESTIntegrationConnector for
|
|
94
|
+
* template-variable resolution and pagination. We intercept the top-level
|
|
95
|
+
* Sites endpoint because the /sites?search=* syntax is not a standard GET
|
|
96
|
+
* collection — we normalise its response to the value array ourselves.
|
|
97
|
+
*/
|
|
98
|
+
FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
|
|
99
|
+
/**
|
|
100
|
+
* Generic create for every object EXCEPT ListItem, whose Graph create requires the
|
|
101
|
+
* `{ "fields": {...} }` envelope. We re-wrap the attributes for ListItem and execute
|
|
102
|
+
* the same generic mechanics (auth → headers → POST → BuildCreatedResult), so the
|
|
103
|
+
* loud-on-empty-ID guarantee is preserved.
|
|
104
|
+
*/
|
|
105
|
+
CreateRecord(ctx: CreateRecordContext): Promise<CRUDResult>;
|
|
106
|
+
/**
|
|
107
|
+
* Authenticates with Azure AD via client-credentials flow.
|
|
108
|
+
* Caches the bearer token until within TOKEN_REFRESH_BUFFER_MS of expiry.
|
|
109
|
+
*/
|
|
110
|
+
protected Authenticate(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo, forceRefresh?: boolean): Promise<SharePointAuthContext>;
|
|
111
|
+
protected BuildHeaders(auth: RESTAuthContext): Record<string, string>;
|
|
112
|
+
/**
|
|
113
|
+
* HTTP transport with rate-limit throttling, Retry-After honoring, and
|
|
114
|
+
* exponential backoff on 429/503.
|
|
115
|
+
*/
|
|
116
|
+
protected MakeHTTPRequest(auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
|
|
117
|
+
/**
|
|
118
|
+
* Extracts the `value` array from a Graph response envelope. The base class
|
|
119
|
+
* already passes `ResponseDataKey` from metadata — we default to the `value`
|
|
120
|
+
* convention when responseDataKey is null.
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* Scope filter: a SharePoint *document-library* connector enumerates SharePoint sites
|
|
124
|
+
* (team/communication sites under `<tenant>.sharepoint.com/sites/...`), NOT users' personal
|
|
125
|
+
* OneDrive sites (`<tenant>-my.sharepoint.com/personal/...`). Personal sites are a different
|
|
126
|
+
* product (OneDrive), are routinely admin-locked (Graph returns HTTP 423 `resourceLocked` on
|
|
127
|
+
* their `/drives`), and carry no SharePoint document libraries — so iterating Drive/DriveItem
|
|
128
|
+
* over them yields only errors and starves the traversal before it reaches real document sites.
|
|
129
|
+
* We drop them at the Site source so they never become parents for the second-layer objects.
|
|
130
|
+
* Only Site records carry a `webUrl` on the `-my` host, so this is a no-op for every other object.
|
|
131
|
+
*/
|
|
132
|
+
private ExcludePersonalSites;
|
|
133
|
+
protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
|
|
134
|
+
/**
|
|
135
|
+
* Extracts pagination state from the Graph `@odata.nextLink` annotation.
|
|
136
|
+
* Graph uses opaque URL cursors — we store the full nextLink URL in the
|
|
137
|
+
* cursor so the next iteration issues the exact request Graph expects.
|
|
138
|
+
*/
|
|
139
|
+
protected ExtractPaginationInfo(rawBody: unknown, _paginationType: PaginationType, _currentPage: number, _currentOffset: number, _pageSize: number): PaginationState;
|
|
140
|
+
protected GetBaseURL(_companyIntegration: MJCompanyIntegrationEntity, auth: RESTAuthContext): string;
|
|
141
|
+
/**
|
|
142
|
+
* Overrides the base pagination URL builder. Graph's nextLink is an absolute
|
|
143
|
+
* URL that encodes the full continuation request. When we have a cursor we
|
|
144
|
+
* use it directly; otherwise we rely on the base path (already wired with
|
|
145
|
+
* $top / $select via DefaultQueryParams).
|
|
146
|
+
*/
|
|
147
|
+
protected BuildPaginatedURL(basePath: string, obj: MJIntegrationObjectEntity, _page: number, _offset: number, cursor?: string, effectivePageSize?: number): string;
|
|
148
|
+
private IsTokenValid;
|
|
149
|
+
private RequestGraphToken;
|
|
150
|
+
private ParseConfig;
|
|
151
|
+
private LoadFromCredentialEntity;
|
|
152
|
+
private ValidateConfig;
|
|
153
|
+
private ExecuteOneRequest;
|
|
154
|
+
private ParseResponseBody;
|
|
155
|
+
private ExtractHeaders;
|
|
156
|
+
private IsRetryable;
|
|
157
|
+
private ComputeBackoffDelay;
|
|
158
|
+
private Throttle;
|
|
159
|
+
private Sleep;
|
|
160
|
+
private ValidateResponse;
|
|
161
|
+
/**
|
|
162
|
+
* Detects whether an IntegrationObject supports Graph `/delta` queries.
|
|
163
|
+
* Per the frozen contract, exactly Site, DriveItem, and ListItem carry
|
|
164
|
+
* `IncrementalWatermarkField=@odata.deltaLink`.
|
|
165
|
+
*/
|
|
166
|
+
private SupportsDeltaForObject;
|
|
167
|
+
/**
|
|
168
|
+
* Fetches changed records via Graph's /delta endpoint. The `WatermarkValue`
|
|
169
|
+
* holds either a full delta URL (from the previous batch) or a token to
|
|
170
|
+
* append to the delta endpoint.
|
|
171
|
+
*/
|
|
172
|
+
private FetchChangesViaDelta;
|
|
173
|
+
private BuildDeltaUrl;
|
|
174
|
+
/**
|
|
175
|
+
* Enumerates every accessible (site, list) pair and fetches each list's
|
|
176
|
+
* column definitions, returning a deduplicated array of fields not already
|
|
177
|
+
* present in the static metadata.
|
|
178
|
+
*
|
|
179
|
+
* Note: For large tenants this can be expensive. Callers typically scope
|
|
180
|
+
* this to specific sites via ExtraFilter / configuration.
|
|
181
|
+
*/
|
|
182
|
+
private DiscoverListColumnsForAllLists;
|
|
183
|
+
private ListAllSites;
|
|
184
|
+
private ListListsForSite;
|
|
185
|
+
private ListColumnsForList;
|
|
186
|
+
private GraphColumnToFieldSchema;
|
|
187
|
+
private InferGraphColumnType;
|
|
188
|
+
}
|
|
189
|
+
/** Tree-shaking prevention function — import and call from module entry point. */
|
|
190
|
+
export declare function LoadSharePointConnector(): void;
|
|
191
|
+
export {};
|
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
8
|
+
import { Metadata } from '@memberjunction/core';
|
|
9
|
+
import { BaseIntegrationConnector, BaseRESTIntegrationConnector, } from '@memberjunction/integration-engine';
|
|
10
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
11
|
+
/** Default Graph base URL (production tenant, v1.0). */
|
|
12
|
+
const GRAPH_V1_BASE_URL = 'https://graph.microsoft.com/v1.0';
|
|
13
|
+
/** Default OAuth scope for app-only Graph access. */
|
|
14
|
+
const DEFAULT_SCOPE = 'https://graph.microsoft.com/.default';
|
|
15
|
+
/** Default Azure AD authority host (public cloud). Overridden via config.AuthorityHost for sovereign clouds. */
|
|
16
|
+
const DEFAULT_AUTHORITY_HOST = 'https://login.microsoftonline.com';
|
|
17
|
+
/** Azure AD token endpoint template. authorityHost defaults to the public-cloud host; override for
|
|
18
|
+
* sovereign clouds (Azure Gov / China) via SharePointConnectionConfig.AuthorityHost. */
|
|
19
|
+
const AAD_TOKEN_ENDPOINT = (tenantId, authorityHost = DEFAULT_AUTHORITY_HOST) => `${authorityHost.replace(/\/+$/, '')}/${encodeURIComponent(tenantId)}/oauth2/v2.0/token`;
|
|
20
|
+
/** Default minimum interval between API calls (Graph baseline is ~4 req/s). */
|
|
21
|
+
const DEFAULT_MIN_REQUEST_INTERVAL_MS = 250;
|
|
22
|
+
/** Default HTTP request timeout. */
|
|
23
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
24
|
+
/** Default retry count for retryable errors. */
|
|
25
|
+
const DEFAULT_MAX_RETRIES = 5;
|
|
26
|
+
/** Buffer before token expiry at which to refresh (60s). */
|
|
27
|
+
const TOKEN_REFRESH_BUFFER_MS = 60 * 1000;
|
|
28
|
+
/**
|
|
29
|
+
* IntegrationObject name whose runtime field discovery augments static metadata
|
|
30
|
+
* with per-list column definitions. Matches the frozen-contract object name `ListItem`.
|
|
31
|
+
*/
|
|
32
|
+
const LIST_ITEM_OBJECT = 'ListItem';
|
|
33
|
+
/**
|
|
34
|
+
* Object names that support Microsoft Graph `/delta` incremental queries.
|
|
35
|
+
* Per the re-derived contract, exactly Site, DriveItem, and ListItem carry
|
|
36
|
+
* `IncrementalWatermarkField=@odata.deltaLink`; everything else is full-scan.
|
|
37
|
+
*/
|
|
38
|
+
const DELTA_OBJECTS = new Set(['Site', 'DriveItem', 'ListItem']);
|
|
39
|
+
/**
|
|
40
|
+
* Objects whose Microsoft Graph CREATE shape is genuinely idiosyncratic and cannot be
|
|
41
|
+
* expressed by the generic flat/wrapped BodyShape columns, so CreateRecord is overridden
|
|
42
|
+
* for them (and ONLY them). Everything else uses the generic per-operation CRUD path.
|
|
43
|
+
*
|
|
44
|
+
* - ListItem: `POST /sites/{site}/lists/{list}/items` requires the column values nested
|
|
45
|
+
* under a `fields` envelope: `{ "fields": { Title: "x", ... } }`. The metadata declares
|
|
46
|
+
* `CreateBodyShape=flat` (because the UPDATE path `/items/{id}/fields` PATCHes the flat
|
|
47
|
+
* map directly — create and update are asymmetric in Graph), so the generic flat create
|
|
48
|
+
* would POST the bare map and Graph rejects it. We re-wrap here. The override STILL routes
|
|
49
|
+
* through BuildCreatedResult so a 2xx-with-no-id fails loudly.
|
|
50
|
+
*/
|
|
51
|
+
const LISTITEM_CREATE_OBJECT = 'ListItem';
|
|
52
|
+
// ─── Connector Implementation ────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Connector for Microsoft SharePoint Online via Microsoft Graph v1.0.
|
|
55
|
+
*
|
|
56
|
+
* Extends BaseRESTIntegrationConnector — inherits pagination + template variable
|
|
57
|
+
* substitution from metadata. Template vars like `{id}` / `{siteId}` are resolved
|
|
58
|
+
* per-parent using IntegrationObject FK / PK metadata, so object hierarchies
|
|
59
|
+
* (sites -> lists -> list items) traverse automatically.
|
|
60
|
+
*
|
|
61
|
+
* Auth flow:
|
|
62
|
+
* 1. Client-credentials OAuth 2.0 against Azure AD
|
|
63
|
+
* 2. Bearer token attached to every Graph request
|
|
64
|
+
* 3. Token is refreshed proactively before expiry
|
|
65
|
+
*
|
|
66
|
+
* Pagination: `@odata.nextLink` cursor (per OData convention) — replayed verbatim.
|
|
67
|
+
*
|
|
68
|
+
* Incremental sync: Graph `/delta` for Site, DriveItem, and ListItem (the three
|
|
69
|
+
* objects the frozen contract proves carry `@odata.deltaLink`). The watermark is
|
|
70
|
+
* the full deltaLink URL, replayed verbatim; the first sync runs as a full fetch.
|
|
71
|
+
*
|
|
72
|
+
* Discovery is non-authoritative (DiscoveryIsAuthoritative inherits false): the 25
|
|
73
|
+
* standard objects come from Declared metadata; runtime field discovery only ADDS
|
|
74
|
+
* tenant-specific list columns. Absence in a refresh never deactivates.
|
|
75
|
+
*/
|
|
76
|
+
let SharePointConnector = class SharePointConnector extends BaseRESTIntegrationConnector {
|
|
77
|
+
constructor() {
|
|
78
|
+
// ── State ────────────────────────────────────────────────────────
|
|
79
|
+
super(...arguments);
|
|
80
|
+
this.cachedAuth = null;
|
|
81
|
+
this.tokenExpiresAt = 0;
|
|
82
|
+
this.lastRequestTime = 0;
|
|
83
|
+
}
|
|
84
|
+
// ── Capability Getters ───────────────────────────────────────────
|
|
85
|
+
// RUNTIME STATUS: this connector is READ-ONLY end-to-end. The global
|
|
86
|
+
// SupportsCreate/Update/Delete getters inherit `false`, and BOTH the
|
|
87
|
+
// IntegrationEngine push path AND the IntegrationWriteRecord resolver gate every
|
|
88
|
+
// write on those GLOBAL getters — so no write executes through the product today,
|
|
89
|
+
// regardless of the per-object metadata. Read sync is what is live-proven.
|
|
90
|
+
//
|
|
91
|
+
// The write surface below (the ListItem CreateRecord override + the Create/Update/
|
|
92
|
+
// Delete columns the frozen contract populates for DriveItem / List / ListItem /
|
|
93
|
+
// Subscription) is implemented and unit-tested, but is intentionally PER-OBJECT, not
|
|
94
|
+
// global: we do NOT flip the global getters to `true`, because that would wrongly
|
|
95
|
+
// advertise writes for Site / Drive / the other read-only objects. It activates only
|
|
96
|
+
// once the engine adds per-object write dispatch (a separate framework change); until
|
|
97
|
+
// then it is dormant by design, and the base generic CRUD throws a clear
|
|
98
|
+
// "not configured" error for any object whose per-operation columns are null.
|
|
99
|
+
/**
|
|
100
|
+
* Verbatim from the frozen contract's Integration.Name AND the baseline-seeded
|
|
101
|
+
* `__mj.Integration` row — both are exactly `'SharePoint'`. This is load-bearing:
|
|
102
|
+
* the three-way invariant `IntegrationName === MJ: Integrations.Name === @RegisterClass
|
|
103
|
+
* driver→ClassName` is how the engine binds this connector to its Integration row. A
|
|
104
|
+
* mismatch (e.g. 'SharePoint Online') means the engine never resolves the connector,
|
|
105
|
+
* no connection is created, and the live sync lands 0 rows. DO NOT change this string.
|
|
106
|
+
*/
|
|
107
|
+
get IntegrationName() { return 'SharePoint'; }
|
|
108
|
+
// ── Action Generation ────────────────────────────────────────────
|
|
109
|
+
//
|
|
110
|
+
// We deliberately do NOT override GetIntegrationObjects / GetActionGeneratorConfig.
|
|
111
|
+
// The object/field catalog is NOT baked in connector code — it lives entirely in the
|
|
112
|
+
// 25 Declared IntegrationObject rows in metadata (case 1: credential-free Graph spec).
|
|
113
|
+
// Baking a module-level catalog constant here is the `catalog-in-code` floor-check
|
|
114
|
+
// failure (it freezes the object set AND becomes a circular source a later build reads
|
|
115
|
+
// its own output back from). The base GetIntegrationObjects() returns [] and the base
|
|
116
|
+
// GetActionGeneratorConfig() returns null when objects are empty — exactly what we want.
|
|
117
|
+
// DiscoverObjects (below) delegates to super, which reads the Declared rows at runtime.
|
|
118
|
+
// ── Default Configuration ────────────────────────────────────────
|
|
119
|
+
GetDefaultConfiguration() {
|
|
120
|
+
return {
|
|
121
|
+
DefaultSchemaName: 'SharePoint',
|
|
122
|
+
DefaultObjects: [
|
|
123
|
+
{
|
|
124
|
+
SourceObjectName: 'Site',
|
|
125
|
+
TargetTableName: 'SharePoint_Site',
|
|
126
|
+
TargetEntityName: 'SharePoint Sites',
|
|
127
|
+
SyncEnabled: true,
|
|
128
|
+
FieldMappings: this.GetDefaultFieldMappings('Site', 'Sites'),
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
SourceObjectName: 'List',
|
|
132
|
+
TargetTableName: 'SharePoint_List',
|
|
133
|
+
TargetEntityName: 'SharePoint Lists',
|
|
134
|
+
SyncEnabled: true,
|
|
135
|
+
FieldMappings: this.GetDefaultFieldMappings('List', 'Lists'),
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
SourceObjectName: 'ListItem',
|
|
139
|
+
TargetTableName: 'SharePoint_ListItem',
|
|
140
|
+
TargetEntityName: 'SharePoint List Items',
|
|
141
|
+
SyncEnabled: true,
|
|
142
|
+
FieldMappings: this.GetDefaultFieldMappings('ListItem', 'ListItems'),
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
GetDefaultFieldMappings(objectName, _entityName) {
|
|
148
|
+
switch (objectName) {
|
|
149
|
+
case 'Site':
|
|
150
|
+
return [
|
|
151
|
+
{ SourceFieldName: 'id', DestinationFieldName: 'ExternalID', IsKeyField: true },
|
|
152
|
+
{ SourceFieldName: 'displayName', DestinationFieldName: 'Name' },
|
|
153
|
+
{ SourceFieldName: 'webUrl', DestinationFieldName: 'URL' },
|
|
154
|
+
{ SourceFieldName: 'description', DestinationFieldName: 'Description' },
|
|
155
|
+
];
|
|
156
|
+
case 'List':
|
|
157
|
+
return [
|
|
158
|
+
{ SourceFieldName: 'id', DestinationFieldName: 'ExternalID', IsKeyField: true },
|
|
159
|
+
{ SourceFieldName: 'displayName', DestinationFieldName: 'Name' },
|
|
160
|
+
{ SourceFieldName: 'description', DestinationFieldName: 'Description' },
|
|
161
|
+
];
|
|
162
|
+
case 'ListItem':
|
|
163
|
+
return [
|
|
164
|
+
{ SourceFieldName: 'id', DestinationFieldName: 'ExternalID', IsKeyField: true },
|
|
165
|
+
];
|
|
166
|
+
default:
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// ── TestConnection ───────────────────────────────────────────────
|
|
171
|
+
/**
|
|
172
|
+
* Verifies the service principal can reach Graph by fetching the tenant's
|
|
173
|
+
* organization record. Forces a token refresh so credentials are validated.
|
|
174
|
+
*/
|
|
175
|
+
async TestConnection(companyIntegration, contextUser) {
|
|
176
|
+
try {
|
|
177
|
+
const auth = await this.Authenticate(companyIntegration, contextUser, true);
|
|
178
|
+
const url = `${auth.BaseUrl}/organization?$select=id,displayName`;
|
|
179
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
|
|
180
|
+
this.ValidateResponse(response, url);
|
|
181
|
+
const body = response.Body;
|
|
182
|
+
const orgName = body.value?.[0]?.displayName ?? 'unknown';
|
|
183
|
+
return {
|
|
184
|
+
Success: true,
|
|
185
|
+
Message: `Successfully connected to Microsoft Graph (tenant: ${orgName})`,
|
|
186
|
+
ServerVersion: 'Microsoft Graph v1.0',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
191
|
+
return { Success: false, Message: `Connection failed: ${message}` };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// ── DiscoverObjects / DiscoverFields ─────────────────────────────
|
|
195
|
+
/**
|
|
196
|
+
* Returns the static IntegrationObject list. Discovery of per-site custom
|
|
197
|
+
* lists happens via the SiteLists IntegrationObject's FetchChanges loop, not
|
|
198
|
+
* here — this is a capability catalog, not a live enumeration.
|
|
199
|
+
*/
|
|
200
|
+
async DiscoverObjects(companyIntegration, contextUser) {
|
|
201
|
+
return super.DiscoverObjects(companyIntegration, contextUser);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns static field metadata from IntegrationEngineBase, plus — for
|
|
205
|
+
* SiteListItems — augments with live list-column discovery per list.
|
|
206
|
+
* Custom columns are marked via the IsReadOnly=false / isSealed=false
|
|
207
|
+
* Graph-reported flags; callers downstream can set IsCustom accordingly.
|
|
208
|
+
*/
|
|
209
|
+
async DiscoverFields(companyIntegration, objectName, contextUser) {
|
|
210
|
+
const staticFields = await super.DiscoverFields(companyIntegration, objectName, contextUser);
|
|
211
|
+
if (objectName !== LIST_ITEM_OBJECT)
|
|
212
|
+
return staticFields;
|
|
213
|
+
const custom = await this.DiscoverListColumnsForAllLists(companyIntegration, contextUser, staticFields);
|
|
214
|
+
return [...staticFields, ...custom];
|
|
215
|
+
}
|
|
216
|
+
// ── FetchChanges (Template Variable / Delta hooks) ───────────────
|
|
217
|
+
/**
|
|
218
|
+
* Top-level FetchChanges delegates to BaseRESTIntegrationConnector for
|
|
219
|
+
* template-variable resolution and pagination. We intercept the top-level
|
|
220
|
+
* Sites endpoint because the /sites?search=* syntax is not a standard GET
|
|
221
|
+
* collection — we normalise its response to the value array ourselves.
|
|
222
|
+
*/
|
|
223
|
+
async FetchChanges(ctx) {
|
|
224
|
+
const obj = this.GetCachedObject(ctx.CompanyIntegration.IntegrationID, ctx.ObjectName);
|
|
225
|
+
// Delta sync path — only when the watermark is a full, absolute Graph delta
|
|
226
|
+
// URL (the verbatim @odata.deltaLink from a previous batch). The first sync
|
|
227
|
+
// has no delta link yet, so it falls through to the base full fetch, which
|
|
228
|
+
// does the parent-chain template traversal and yields the deltaLink for next
|
|
229
|
+
// time. We never synthesise a delta URL from a bare token.
|
|
230
|
+
const wm = ctx.WatermarkValue;
|
|
231
|
+
if (wm && /^https?:\/\//.test(wm) && obj.SupportsIncrementalSync && this.SupportsDeltaForObject(obj)) {
|
|
232
|
+
return this.FetchChangesViaDelta(ctx, obj);
|
|
233
|
+
}
|
|
234
|
+
return super.FetchChanges(ctx);
|
|
235
|
+
}
|
|
236
|
+
// ── CRUD operations ──────────────────────────────────────────────
|
|
237
|
+
//
|
|
238
|
+
// Update / Delete / Get use the GENERIC BaseRESTIntegrationConnector path verbatim:
|
|
239
|
+
// the frozen contract fully populates the per-operation columns for the writable IOs
|
|
240
|
+
// (DriveItem / List / ListItem / Subscription) — Update/DeleteAPIPath/Method/BodyShape/
|
|
241
|
+
// IDLocation — including ListItem's Graph-specific `/items/{id}/fields` PATCH path,
|
|
242
|
+
// whose flat body the generic `flat` shape sends correctly. We do NOT override those.
|
|
243
|
+
//
|
|
244
|
+
// Create is overridden for EXACTLY ONE object — ListItem — because Graph's
|
|
245
|
+
// `POST .../items` is the one create whose envelope (`{ "fields": {...} }`) cannot be
|
|
246
|
+
// expressed by the flat/wrapped columns (create is asymmetric to the flat `/fields`
|
|
247
|
+
// PATCH update). Every other object's create falls straight through to the generic
|
|
248
|
+
// path; the ListItem branch STILL routes through BuildCreatedResult so a 2xx with no
|
|
249
|
+
// ID fails loudly (the HubSpot silent-loss guard).
|
|
250
|
+
//
|
|
251
|
+
// (DriveItem *content* upload — Graph's `createUploadSession` chunked PUT — is a
|
|
252
|
+
// separate, multi-step write that is NOT part of the frozen contract's CRUD surface;
|
|
253
|
+
// DriveItem create here is the metadata POST that the generic path handles. If/when
|
|
254
|
+
// content upload is added it belongs in its own override, also via BuildCreatedResult.)
|
|
255
|
+
/**
|
|
256
|
+
* Generic create for every object EXCEPT ListItem, whose Graph create requires the
|
|
257
|
+
* `{ "fields": {...} }` envelope. We re-wrap the attributes for ListItem and execute
|
|
258
|
+
* the same generic mechanics (auth → headers → POST → BuildCreatedResult), so the
|
|
259
|
+
* loud-on-empty-ID guarantee is preserved.
|
|
260
|
+
*/
|
|
261
|
+
async CreateRecord(ctx) {
|
|
262
|
+
if (ctx.ObjectName !== LISTITEM_CREATE_OBJECT) {
|
|
263
|
+
return super.CreateRecord(ctx);
|
|
264
|
+
}
|
|
265
|
+
const ci = ctx.CompanyIntegration;
|
|
266
|
+
const contextUser = ctx.ContextUser;
|
|
267
|
+
const obj = this.GetCachedObject(ci.IntegrationID, ctx.ObjectName);
|
|
268
|
+
if (!obj.CreateAPIPath || !obj.CreateMethod) {
|
|
269
|
+
throw new Error(`CreateRecord not supported for "${ctx.ObjectName}": ` +
|
|
270
|
+
`CreateAPIPath / CreateMethod not configured on IntegrationObject.`);
|
|
271
|
+
}
|
|
272
|
+
const auth = await this.Authenticate(ci, contextUser);
|
|
273
|
+
const headers = this.BuildHeaders(auth);
|
|
274
|
+
const baseURL = this.GetBaseURL(ci, auth);
|
|
275
|
+
const url = `${baseURL.replace(/\/+$/, '')}${obj.CreateAPIPath.startsWith('/') ? '' : '/'}${obj.CreateAPIPath}`;
|
|
276
|
+
// The one idiosyncrasy: Graph wants the column map under `fields`. If the caller
|
|
277
|
+
// already nested it (idempotent), don't double-wrap.
|
|
278
|
+
const attrs = ctx.Attributes;
|
|
279
|
+
const body = ('fields' in attrs && typeof attrs.fields === 'object')
|
|
280
|
+
? attrs
|
|
281
|
+
: { fields: attrs };
|
|
282
|
+
const response = await this.MakeHTTPRequest(auth, url, obj.CreateMethod, headers, body);
|
|
283
|
+
if (response.Status >= 200 && response.Status < 300) {
|
|
284
|
+
const externalID = this.ExtractIDFromResponse(response, obj.CreateIDLocation);
|
|
285
|
+
return this.BuildCreatedResult(externalID, response.Status, ctx.ObjectName);
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
Success: false,
|
|
289
|
+
StatusCode: response.Status,
|
|
290
|
+
ErrorMessage: this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on create`,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
// ─── Abstract BaseRESTIntegrationConnector hooks ────────────────
|
|
294
|
+
/**
|
|
295
|
+
* Authenticates with Azure AD via client-credentials flow.
|
|
296
|
+
* Caches the bearer token until within TOKEN_REFRESH_BUFFER_MS of expiry.
|
|
297
|
+
*/
|
|
298
|
+
async Authenticate(companyIntegration, contextUser, forceRefresh = false) {
|
|
299
|
+
if (!forceRefresh && this.cachedAuth && this.IsTokenValid()) {
|
|
300
|
+
return this.cachedAuth;
|
|
301
|
+
}
|
|
302
|
+
const config = await this.ParseConfig(companyIntegration, contextUser);
|
|
303
|
+
const token = await this.RequestGraphToken(config);
|
|
304
|
+
const baseUrl = config.GraphBaseUrl ?? GRAPH_V1_BASE_URL;
|
|
305
|
+
const auth = {
|
|
306
|
+
Token: token.access_token,
|
|
307
|
+
ExpiresAt: new Date(Date.now() + token.expires_in * 1000),
|
|
308
|
+
Config: config,
|
|
309
|
+
BaseUrl: baseUrl,
|
|
310
|
+
};
|
|
311
|
+
this.cachedAuth = auth;
|
|
312
|
+
this.tokenExpiresAt = Date.now() + token.expires_in * 1000;
|
|
313
|
+
return auth;
|
|
314
|
+
}
|
|
315
|
+
BuildHeaders(auth) {
|
|
316
|
+
const token = auth.Token ?? '';
|
|
317
|
+
return {
|
|
318
|
+
'Authorization': `Bearer ${token}`,
|
|
319
|
+
'Accept': 'application/json',
|
|
320
|
+
'Content-Type': 'application/json',
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* HTTP transport with rate-limit throttling, Retry-After honoring, and
|
|
325
|
+
* exponential backoff on 429/503.
|
|
326
|
+
*/
|
|
327
|
+
async MakeHTTPRequest(auth, url, method, headers, body) {
|
|
328
|
+
const spAuth = auth;
|
|
329
|
+
const config = spAuth.Config;
|
|
330
|
+
const maxRetries = config.MaxRetries ?? DEFAULT_MAX_RETRIES;
|
|
331
|
+
const timeoutMs = config.RequestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
332
|
+
const minInterval = config.MinRequestIntervalMs ?? DEFAULT_MIN_REQUEST_INTERVAL_MS;
|
|
333
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
334
|
+
await this.Throttle(minInterval);
|
|
335
|
+
const response = await this.ExecuteOneRequest(url, method, headers, body, timeoutMs);
|
|
336
|
+
if (this.IsRetryable(response) && attempt < maxRetries) {
|
|
337
|
+
const delay = this.ComputeBackoffDelay(attempt, response.Headers['retry-after']);
|
|
338
|
+
await this.Sleep(delay);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
return response;
|
|
342
|
+
}
|
|
343
|
+
throw new Error(`SharePointConnector: exhausted ${maxRetries + 1} attempts for ${method} ${url}`);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Extracts the `value` array from a Graph response envelope. The base class
|
|
347
|
+
* already passes `ResponseDataKey` from metadata — we default to the `value`
|
|
348
|
+
* convention when responseDataKey is null.
|
|
349
|
+
*/
|
|
350
|
+
/**
|
|
351
|
+
* Scope filter: a SharePoint *document-library* connector enumerates SharePoint sites
|
|
352
|
+
* (team/communication sites under `<tenant>.sharepoint.com/sites/...`), NOT users' personal
|
|
353
|
+
* OneDrive sites (`<tenant>-my.sharepoint.com/personal/...`). Personal sites are a different
|
|
354
|
+
* product (OneDrive), are routinely admin-locked (Graph returns HTTP 423 `resourceLocked` on
|
|
355
|
+
* their `/drives`), and carry no SharePoint document libraries — so iterating Drive/DriveItem
|
|
356
|
+
* over them yields only errors and starves the traversal before it reaches real document sites.
|
|
357
|
+
* We drop them at the Site source so they never become parents for the second-layer objects.
|
|
358
|
+
* Only Site records carry a `webUrl` on the `-my` host, so this is a no-op for every other object.
|
|
359
|
+
*/
|
|
360
|
+
ExcludePersonalSites(records) {
|
|
361
|
+
return records.filter(r => {
|
|
362
|
+
const webUrl = typeof r.webUrl === 'string' ? r.webUrl : '';
|
|
363
|
+
const isPersonal = r.isPersonalSite === true || webUrl.includes('-my.sharepoint.com');
|
|
364
|
+
return !isPersonal;
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
NormalizeResponse(rawBody, responseDataKey) {
|
|
368
|
+
const body = rawBody;
|
|
369
|
+
const key = responseDataKey ?? 'value';
|
|
370
|
+
const data = body[key];
|
|
371
|
+
if (Array.isArray(data))
|
|
372
|
+
return this.ExcludePersonalSites(data);
|
|
373
|
+
// Single-record response fallback
|
|
374
|
+
if (body && typeof body === 'object' && 'id' in body)
|
|
375
|
+
return this.ExcludePersonalSites([body]);
|
|
376
|
+
return [];
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Extracts pagination state from the Graph `@odata.nextLink` annotation.
|
|
380
|
+
* Graph uses opaque URL cursors — we store the full nextLink URL in the
|
|
381
|
+
* cursor so the next iteration issues the exact request Graph expects.
|
|
382
|
+
*/
|
|
383
|
+
ExtractPaginationInfo(rawBody, _paginationType, _currentPage, _currentOffset, _pageSize) {
|
|
384
|
+
const body = rawBody;
|
|
385
|
+
const nextLink = body?.['@odata.nextLink'];
|
|
386
|
+
return {
|
|
387
|
+
HasMore: typeof nextLink === 'string' && nextLink.length > 0,
|
|
388
|
+
NextCursor: nextLink,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
GetBaseURL(_companyIntegration, auth) {
|
|
392
|
+
const spAuth = auth;
|
|
393
|
+
return spAuth.BaseUrl;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Overrides the base pagination URL builder. Graph's nextLink is an absolute
|
|
397
|
+
* URL that encodes the full continuation request. When we have a cursor we
|
|
398
|
+
* use it directly; otherwise we rely on the base path (already wired with
|
|
399
|
+
* $top / $select via DefaultQueryParams).
|
|
400
|
+
*/
|
|
401
|
+
BuildPaginatedURL(basePath, obj, _page, _offset, cursor, effectivePageSize) {
|
|
402
|
+
if (cursor && cursor.length > 0)
|
|
403
|
+
return cursor;
|
|
404
|
+
const pageSize = effectivePageSize ?? obj.DefaultPageSize ?? 200;
|
|
405
|
+
const separator = basePath.includes('?') ? '&' : '?';
|
|
406
|
+
return `${basePath}${separator}$top=${pageSize}`;
|
|
407
|
+
}
|
|
408
|
+
// ─── Token Management ────────────────────────────────────────────
|
|
409
|
+
IsTokenValid() {
|
|
410
|
+
if (!this.cachedAuth || !this.cachedAuth.Token)
|
|
411
|
+
return false;
|
|
412
|
+
return Date.now() < this.tokenExpiresAt - TOKEN_REFRESH_BUFFER_MS;
|
|
413
|
+
}
|
|
414
|
+
async RequestGraphToken(config) {
|
|
415
|
+
const url = AAD_TOKEN_ENDPOINT(config.TenantId, config.AuthorityHost);
|
|
416
|
+
const scope = config.Scope ?? DEFAULT_SCOPE;
|
|
417
|
+
const form = new URLSearchParams({
|
|
418
|
+
client_id: config.ClientId,
|
|
419
|
+
scope,
|
|
420
|
+
client_secret: config.ClientSecret,
|
|
421
|
+
grant_type: 'client_credentials',
|
|
422
|
+
});
|
|
423
|
+
const response = await fetch(url, {
|
|
424
|
+
method: 'POST',
|
|
425
|
+
headers: {
|
|
426
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
427
|
+
'Accept': 'application/json',
|
|
428
|
+
},
|
|
429
|
+
body: form.toString(),
|
|
430
|
+
});
|
|
431
|
+
const text = await response.text();
|
|
432
|
+
if (!response.ok) {
|
|
433
|
+
throw new Error(`SharePointConnector: Azure AD token request failed (${response.status}): ${text.slice(0, 500)}`);
|
|
434
|
+
}
|
|
435
|
+
return JSON.parse(text);
|
|
436
|
+
}
|
|
437
|
+
// ─── Configuration Parsing ───────────────────────────────────────
|
|
438
|
+
async ParseConfig(companyIntegration, contextUser) {
|
|
439
|
+
const credentialID = companyIntegration.CredentialID;
|
|
440
|
+
if (credentialID) {
|
|
441
|
+
const config = await this.LoadFromCredentialEntity(credentialID, contextUser);
|
|
442
|
+
if (config)
|
|
443
|
+
return config;
|
|
444
|
+
}
|
|
445
|
+
const configJson = companyIntegration.Configuration;
|
|
446
|
+
if (configJson) {
|
|
447
|
+
const parsed = JSON.parse(configJson);
|
|
448
|
+
return this.ValidateConfig(parsed);
|
|
449
|
+
}
|
|
450
|
+
throw new Error('SharePointConnector: No credentials or configuration found on CompanyIntegration');
|
|
451
|
+
}
|
|
452
|
+
async LoadFromCredentialEntity(credentialID, contextUser, provider) {
|
|
453
|
+
const md = provider ?? new Metadata();
|
|
454
|
+
const credential = await md.GetEntityObject('MJ: Credentials', contextUser);
|
|
455
|
+
const loaded = await credential.Load(credentialID);
|
|
456
|
+
if (!loaded || !credential.Values)
|
|
457
|
+
return null;
|
|
458
|
+
try {
|
|
459
|
+
const raw = JSON.parse(credential.Values);
|
|
460
|
+
const parsed = {
|
|
461
|
+
TenantId: raw.tenantId ?? raw.TenantId,
|
|
462
|
+
ClientId: raw.clientId ?? raw.ClientId,
|
|
463
|
+
ClientSecret: raw.clientSecret ?? raw.ClientSecret,
|
|
464
|
+
GraphBaseUrl: raw.graphBaseUrl ?? raw.GraphBaseUrl,
|
|
465
|
+
Scope: raw.scope ?? raw.Scope,
|
|
466
|
+
AuthorityHost: raw.authorityHost ?? raw.AuthorityHost
|
|
467
|
+
?? raw.authority_host ?? raw.authority,
|
|
468
|
+
};
|
|
469
|
+
return this.ValidateConfig(parsed);
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
ValidateConfig(raw) {
|
|
476
|
+
if (!raw.TenantId)
|
|
477
|
+
throw new Error('SharePointConnector: TenantId is required');
|
|
478
|
+
if (!raw.ClientId)
|
|
479
|
+
throw new Error('SharePointConnector: ClientId is required');
|
|
480
|
+
if (!raw.ClientSecret)
|
|
481
|
+
throw new Error('SharePointConnector: ClientSecret is required');
|
|
482
|
+
return {
|
|
483
|
+
TenantId: raw.TenantId,
|
|
484
|
+
ClientId: raw.ClientId,
|
|
485
|
+
ClientSecret: raw.ClientSecret,
|
|
486
|
+
GraphBaseUrl: raw.GraphBaseUrl,
|
|
487
|
+
Scope: raw.Scope,
|
|
488
|
+
AuthorityHost: raw.AuthorityHost,
|
|
489
|
+
MaxRetries: raw.MaxRetries ?? DEFAULT_MAX_RETRIES,
|
|
490
|
+
RequestTimeoutMs: raw.RequestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
491
|
+
MinRequestIntervalMs: raw.MinRequestIntervalMs ?? DEFAULT_MIN_REQUEST_INTERVAL_MS,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
// ─── HTTP Helpers ────────────────────────────────────────────────
|
|
495
|
+
async ExecuteOneRequest(url, method, headers, body, timeoutMs) {
|
|
496
|
+
const controller = new AbortController();
|
|
497
|
+
const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
|
|
498
|
+
try {
|
|
499
|
+
const response = await fetch(url, {
|
|
500
|
+
method,
|
|
501
|
+
headers,
|
|
502
|
+
body: body !== undefined && method !== 'GET' && method !== 'DELETE'
|
|
503
|
+
? JSON.stringify(body)
|
|
504
|
+
: undefined,
|
|
505
|
+
signal: controller.signal,
|
|
506
|
+
});
|
|
507
|
+
this.lastRequestTime = Date.now();
|
|
508
|
+
const responseHeaders = this.ExtractHeaders(response.headers);
|
|
509
|
+
const parsedBody = await this.ParseResponseBody(response);
|
|
510
|
+
return { Status: response.status, Body: parsedBody, Headers: responseHeaders };
|
|
511
|
+
}
|
|
512
|
+
finally {
|
|
513
|
+
clearTimeout(timeoutHandle);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
async ParseResponseBody(response) {
|
|
517
|
+
const text = await response.text();
|
|
518
|
+
if (!text)
|
|
519
|
+
return null;
|
|
520
|
+
try {
|
|
521
|
+
return JSON.parse(text);
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
return text;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
ExtractHeaders(headers) {
|
|
528
|
+
const map = {};
|
|
529
|
+
headers.forEach((value, key) => {
|
|
530
|
+
map[key.toLowerCase()] = value;
|
|
531
|
+
});
|
|
532
|
+
return map;
|
|
533
|
+
}
|
|
534
|
+
IsRetryable(response) {
|
|
535
|
+
return response.Status === 429 || response.Status === 503 || response.Status === 504;
|
|
536
|
+
}
|
|
537
|
+
ComputeBackoffDelay(attempt, retryAfterHeader) {
|
|
538
|
+
if (retryAfterHeader) {
|
|
539
|
+
const parsed = parseInt(retryAfterHeader, 10);
|
|
540
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
541
|
+
return Math.min(parsed * 1000, 60000);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return Math.min(Math.pow(2, attempt) * 1000, 30000);
|
|
545
|
+
}
|
|
546
|
+
async Throttle(minIntervalMs) {
|
|
547
|
+
const elapsed = Date.now() - this.lastRequestTime;
|
|
548
|
+
if (elapsed < minIntervalMs) {
|
|
549
|
+
await this.Sleep(minIntervalMs - elapsed);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
Sleep(ms) {
|
|
553
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
554
|
+
}
|
|
555
|
+
ValidateResponse(response, url) {
|
|
556
|
+
if (response.Status < 200 || response.Status >= 300) {
|
|
557
|
+
const preview = typeof response.Body === 'string'
|
|
558
|
+
? response.Body.slice(0, 500)
|
|
559
|
+
: JSON.stringify(response.Body).slice(0, 500);
|
|
560
|
+
throw new Error(`Graph HTTP ${response.Status} from ${url}: ${preview}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
// ─── Delta sync ──────────────────────────────────────────────────
|
|
564
|
+
/**
|
|
565
|
+
* Detects whether an IntegrationObject supports Graph `/delta` queries.
|
|
566
|
+
* Per the frozen contract, exactly Site, DriveItem, and ListItem carry
|
|
567
|
+
* `IncrementalWatermarkField=@odata.deltaLink`.
|
|
568
|
+
*/
|
|
569
|
+
SupportsDeltaForObject(obj) {
|
|
570
|
+
return DELTA_OBJECTS.has(obj.Name);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Fetches changed records via Graph's /delta endpoint. The `WatermarkValue`
|
|
574
|
+
* holds either a full delta URL (from the previous batch) or a token to
|
|
575
|
+
* append to the delta endpoint.
|
|
576
|
+
*/
|
|
577
|
+
async FetchChangesViaDelta(ctx, obj) {
|
|
578
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
579
|
+
const deltaUrl = this.BuildDeltaUrl(auth, obj, ctx.WatermarkValue);
|
|
580
|
+
const response = await this.MakeHTTPRequest(auth, deltaUrl, 'GET', this.BuildHeaders(auth));
|
|
581
|
+
this.ValidateResponse(response, deltaUrl);
|
|
582
|
+
const body = response.Body;
|
|
583
|
+
const records = body.value ?? [];
|
|
584
|
+
const nextLink = body['@odata.nextLink'];
|
|
585
|
+
const deltaLink = body['@odata.deltaLink'];
|
|
586
|
+
const externalRecords = records.map(r => ({
|
|
587
|
+
ExternalID: String(r['id'] ?? ''),
|
|
588
|
+
ObjectType: ctx.ObjectName,
|
|
589
|
+
Fields: r,
|
|
590
|
+
ModifiedAt: typeof r['lastModifiedDateTime'] === 'string'
|
|
591
|
+
? new Date(r['lastModifiedDateTime']) : undefined,
|
|
592
|
+
// Microsoft Graph delta deletion semantics: driveItem and listItem use the
|
|
593
|
+
// `deleted` facet (e.g. `"deleted": { "state": "deleted" }`). The legacy
|
|
594
|
+
// `@removed` shape applies to directoryObjects (users/groups) only. Check
|
|
595
|
+
// both so we catch deletions across the resource types this connector reaches.
|
|
596
|
+
IsDeleted: (typeof r['deleted'] === 'object' && r['deleted'] !== null) ||
|
|
597
|
+
(typeof r['@removed'] === 'object' && r['@removed'] !== null),
|
|
598
|
+
}));
|
|
599
|
+
return {
|
|
600
|
+
Records: externalRecords,
|
|
601
|
+
HasMore: Boolean(nextLink),
|
|
602
|
+
NewWatermarkValue: deltaLink ?? nextLink,
|
|
603
|
+
NextCursor: nextLink,
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
BuildDeltaUrl(_auth, _obj, watermark) {
|
|
607
|
+
// The watermark IS the verbatim `@odata.deltaLink` (or `@odata.nextLink`) URL
|
|
608
|
+
// returned by Graph on the previous batch — a complete, absolute continuation
|
|
609
|
+
// request. We never reconstruct it from a token: Graph's delta/next links are
|
|
610
|
+
// opaque and must be replayed exactly as returned (the same VERBATIM rule as
|
|
611
|
+
// ExtractPaginationInfo's @odata.nextLink handling).
|
|
612
|
+
if (watermark && /^https?:\/\//.test(watermark))
|
|
613
|
+
return watermark;
|
|
614
|
+
// No usable delta link yet (first sync) — caller gates on this; we should not
|
|
615
|
+
// be here without an absolute delta URL.
|
|
616
|
+
throw new Error(`SharePointConnector: delta sync for "${_obj.Name}" requires a full @odata.deltaLink ` +
|
|
617
|
+
`watermark; got "${watermark ?? 'null'}". First-time sync must run via full fetch.`);
|
|
618
|
+
}
|
|
619
|
+
// ─── Runtime List-Column Discovery (Custom Fields) ───────────────
|
|
620
|
+
/**
|
|
621
|
+
* Enumerates every accessible (site, list) pair and fetches each list's
|
|
622
|
+
* column definitions, returning a deduplicated array of fields not already
|
|
623
|
+
* present in the static metadata.
|
|
624
|
+
*
|
|
625
|
+
* Note: For large tenants this can be expensive. Callers typically scope
|
|
626
|
+
* this to specific sites via ExtraFilter / configuration.
|
|
627
|
+
*/
|
|
628
|
+
async DiscoverListColumnsForAllLists(companyIntegration, contextUser, staticFields) {
|
|
629
|
+
try {
|
|
630
|
+
const auth = await this.Authenticate(companyIntegration, contextUser);
|
|
631
|
+
const sites = await this.ListAllSites(auth);
|
|
632
|
+
const staticFieldNames = new Set(staticFields.map(f => f.Name.toLowerCase()));
|
|
633
|
+
const seen = new Set();
|
|
634
|
+
const results = [];
|
|
635
|
+
for (const site of sites) {
|
|
636
|
+
const lists = await this.ListListsForSite(auth, site.id);
|
|
637
|
+
for (const list of lists) {
|
|
638
|
+
const columns = await this.ListColumnsForList(auth, site.id, list.id);
|
|
639
|
+
for (const col of columns) {
|
|
640
|
+
const name = col.name ?? col.id;
|
|
641
|
+
if (!name)
|
|
642
|
+
continue;
|
|
643
|
+
const key = name.toLowerCase();
|
|
644
|
+
if (staticFieldNames.has(key) || seen.has(key))
|
|
645
|
+
continue;
|
|
646
|
+
seen.add(key);
|
|
647
|
+
results.push(this.GraphColumnToFieldSchema(col));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return results;
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
// Best-effort — degrade gracefully if live discovery fails
|
|
655
|
+
return [];
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
async ListAllSites(auth) {
|
|
659
|
+
const url = `${auth.BaseUrl}/sites?search=*&$select=id,displayName,name,webUrl`;
|
|
660
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
|
|
661
|
+
this.ValidateResponse(response, url);
|
|
662
|
+
const body = response.Body;
|
|
663
|
+
return body.value ?? [];
|
|
664
|
+
}
|
|
665
|
+
async ListListsForSite(auth, siteId) {
|
|
666
|
+
const url = `${auth.BaseUrl}/sites/${encodeURIComponent(siteId)}/lists?$select=id,name,displayName`;
|
|
667
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
|
|
668
|
+
if (response.Status >= 400)
|
|
669
|
+
return [];
|
|
670
|
+
const body = response.Body;
|
|
671
|
+
return body.value ?? [];
|
|
672
|
+
}
|
|
673
|
+
async ListColumnsForList(auth, siteId, listId) {
|
|
674
|
+
const url = `${auth.BaseUrl}/sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listId)}/columns`;
|
|
675
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
|
|
676
|
+
if (response.Status >= 400)
|
|
677
|
+
return [];
|
|
678
|
+
const body = response.Body;
|
|
679
|
+
return body.value ?? [];
|
|
680
|
+
}
|
|
681
|
+
GraphColumnToFieldSchema(col) {
|
|
682
|
+
return {
|
|
683
|
+
Name: col.name ?? col.id ?? 'unknown',
|
|
684
|
+
Label: col.displayName ?? col.name ?? col.id ?? 'unknown',
|
|
685
|
+
Description: col.description ?? undefined,
|
|
686
|
+
DataType: this.InferGraphColumnType(col),
|
|
687
|
+
IsRequired: col.required === true,
|
|
688
|
+
IsUniqueKey: false,
|
|
689
|
+
IsReadOnly: col.readOnly === true,
|
|
690
|
+
IsForeignKey: false,
|
|
691
|
+
ForeignKeyTarget: null,
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
InferGraphColumnType(col) {
|
|
695
|
+
if (col.text)
|
|
696
|
+
return 'string';
|
|
697
|
+
if (col.number)
|
|
698
|
+
return 'decimal';
|
|
699
|
+
if (col.boolean)
|
|
700
|
+
return 'boolean';
|
|
701
|
+
if (col.dateTime)
|
|
702
|
+
return 'datetime';
|
|
703
|
+
if (col.choice)
|
|
704
|
+
return 'string';
|
|
705
|
+
if (col.currency)
|
|
706
|
+
return 'decimal';
|
|
707
|
+
if (col.lookup)
|
|
708
|
+
return 'string';
|
|
709
|
+
if (col.personOrGroup)
|
|
710
|
+
return 'string';
|
|
711
|
+
if (col.hyperlinkOrPicture)
|
|
712
|
+
return 'string';
|
|
713
|
+
return 'string';
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
SharePointConnector = __decorate([
|
|
717
|
+
RegisterClass(BaseIntegrationConnector, '@memberjunction/connector-sharepoint')
|
|
718
|
+
], SharePointConnector);
|
|
719
|
+
export { SharePointConnector };
|
|
720
|
+
/** Tree-shaking prevention function — import and call from module entry point. */
|
|
721
|
+
export function LoadSharePointConnector() { }
|
|
722
|
+
//# sourceMappingURL=SharePointConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharePointConnector.js","sourceRoot":"","sources":["../src/SharePointConnector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * from './SharePointConnector.js';
|
|
2
|
+
/** Open App bootstrap entry: importing this module ran the connector's @RegisterClass decorator;
|
|
3
|
+
* this no-op satisfies the loader's required startupExport and forces the import at MJAPI boot. */
|
|
4
|
+
export declare function registerConnector(): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './SharePointConnector.js';
|
|
2
|
+
/** Open App bootstrap entry: importing this module ran the connector's @RegisterClass decorator;
|
|
3
|
+
* this no-op satisfies the loader's required startupExport and forces the import at MJAPI boot. */
|
|
4
|
+
export function registerConnector() { }
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AAEzC;oGACoG;AACpG,MAAM,UAAU,iBAAiB,KAAiD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memberjunction/connector-sharepoint",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MemberJunction SharePoint connector.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"/dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc && tsc-alias -f",
|
|
13
|
+
"test": "vitest run --passWithNoTests"
|
|
14
|
+
},
|
|
15
|
+
"author": "MemberJunction.com",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@memberjunction/core": ">=5.42.0 <6.0.0",
|
|
19
|
+
"@memberjunction/core-entities": ">=5.42.0 <6.0.0",
|
|
20
|
+
"@memberjunction/global": ">=5.42.0 <6.0.0",
|
|
21
|
+
"@memberjunction/integration-engine": ">=5.42.0 <6.0.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "24.10.11",
|
|
26
|
+
"tsc-alias": "^1.8.16",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vitest": "^4.0.18",
|
|
29
|
+
"@memberjunction/core": "^5.42.0",
|
|
30
|
+
"@memberjunction/core-entities": "^5.42.0",
|
|
31
|
+
"@memberjunction/global": "^5.42.0",
|
|
32
|
+
"@memberjunction/integration-engine": "^5.42.0"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/MemberJunction/Integrations"
|
|
37
|
+
}
|
|
38
|
+
}
|