@drawbridge/drawbridge-utils 0.0.136 → 0.0.139
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/connections/index.cjs +175 -29
- package/dist/connections/index.d.cts +230 -15
- package/dist/connections/index.d.ts +230 -15
- package/dist/connections/index.js +175 -29
- package/dist/providers.cjs +181 -35
- package/dist/providers.d.cts +2 -0
- package/dist/providers.d.ts +2 -0
- package/dist/providers.js +181 -35
- package/package.json +1 -1
|
@@ -565,6 +565,9 @@ var attentive_default2 = {
|
|
|
565
565
|
},
|
|
566
566
|
// A contact destination, like Klaviyo and Mailchimp — a merchant could
|
|
567
567
|
// reasonably keep several up to date at once.
|
|
568
|
+
// No vendor-facing event identities — declared empty so the contract stays
|
|
569
|
+
// explicit: a vendor that gains one adds it here, never as a side channel.
|
|
570
|
+
events: {},
|
|
568
571
|
exclusive: false,
|
|
569
572
|
feature: "organization:connection:attentive",
|
|
570
573
|
fields: [
|
|
@@ -1745,6 +1748,9 @@ var drawbridge_default2 = {
|
|
|
1745
1748
|
"Nothing to do. These steps are available in every workflow builder."
|
|
1746
1749
|
]
|
|
1747
1750
|
},
|
|
1751
|
+
// No vendor-facing event identities — declared empty so the contract stays
|
|
1752
|
+
// explicit: a vendor that gains one adds it here, never as a side channel.
|
|
1753
|
+
events: {},
|
|
1748
1754
|
exclusive: false,
|
|
1749
1755
|
fields: [],
|
|
1750
1756
|
group: "developer",
|
|
@@ -2529,6 +2535,9 @@ var klaviyo_default2 = {
|
|
|
2529
2535
|
// current — so the exclusivity that once applied when these were SENDERS is
|
|
2530
2536
|
// deliberately gone. That was removed once already; declaring it out loud is
|
|
2531
2537
|
// what stops it coming back by inference.
|
|
2538
|
+
// No vendor-facing event identities — declared empty so the contract stays
|
|
2539
|
+
// explicit: a vendor that gains one adds it here, never as a side channel.
|
|
2540
|
+
events: {},
|
|
2532
2541
|
exclusive: false,
|
|
2533
2542
|
feature: "organization:connection:klaviyo",
|
|
2534
2543
|
fields: [
|
|
@@ -3005,6 +3014,9 @@ var mailchimp_default2 = {
|
|
|
3005
3014
|
// picking two providers to send the same mail was meaningless. As contact
|
|
3006
3015
|
// syncs they are destinations, and a merchant could reasonably keep several
|
|
3007
3016
|
// up to date, so the exclusivity is gone.
|
|
3017
|
+
// No vendor-facing event identities — declared empty so the contract stays
|
|
3018
|
+
// explicit: a vendor that gains one adds it here, never as a side channel.
|
|
3019
|
+
events: {},
|
|
3008
3020
|
exclusive: false,
|
|
3009
3021
|
feature: "organization:connection:mailchimp",
|
|
3010
3022
|
fields: [
|
|
@@ -3280,6 +3292,22 @@ var toCanonicalEmail = (value) => {
|
|
|
3280
3292
|
return local + "@" + domain;
|
|
3281
3293
|
};
|
|
3282
3294
|
|
|
3295
|
+
// lib/slugify.js
|
|
3296
|
+
import slug from "slugify";
|
|
3297
|
+
var slugify = (value, nochars = false) => {
|
|
3298
|
+
const remove = nochars ? /[-?*+~.()'"!:@#^_{}\[\];,/\\]/g : /[?*+~.()'"!:@#^_{}\[\];,/\\]/g;
|
|
3299
|
+
const replacement = nochars ? "" : "-";
|
|
3300
|
+
return slug(
|
|
3301
|
+
value,
|
|
3302
|
+
{
|
|
3303
|
+
remove,
|
|
3304
|
+
replacement,
|
|
3305
|
+
lower: true,
|
|
3306
|
+
trim: true
|
|
3307
|
+
}
|
|
3308
|
+
);
|
|
3309
|
+
};
|
|
3310
|
+
|
|
3283
3311
|
// lib/connections/providers/shopify.js
|
|
3284
3312
|
var toLine = ({
|
|
3285
3313
|
price,
|
|
@@ -3315,6 +3343,7 @@ var attributeLineItems = (lineItems = []) => lineItems.reduce(
|
|
|
3315
3343
|
{ attrMap: {}, attributedGross: 0, attributedLines: [] }
|
|
3316
3344
|
);
|
|
3317
3345
|
var generateDiscountCode = customAlphabet2("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 8);
|
|
3346
|
+
var ORDER_EVENT_HANDLE = slugify("drawbridge-orders");
|
|
3318
3347
|
var REFRESH_TOKEN_FRESHNESS_BUFFER_MS = 5 * 24 * 60 * 60 * 1e3;
|
|
3319
3348
|
var OAUTH_ERROR_SOURCE = "oauth";
|
|
3320
3349
|
var OAUTH_GRANT_REVOKED_CODES = ["application_cannot_be_found", "invalid_grant"];
|
|
@@ -3372,7 +3401,7 @@ var shopify_default2 = {
|
|
|
3372
3401
|
guide: [
|
|
3373
3402
|
"Open the Drawbridge listing on the Shopify App Store.",
|
|
3374
3403
|
"Install the app on the store you want to connect. It opens in Shopify admin and stays there.",
|
|
3375
|
-
"
|
|
3404
|
+
"Approve the Drawbridge plan when prompted \u2014 during install, or from the connection page here. The connection shows Pending until you do, then Active.",
|
|
3376
3405
|
"Come back here \u2014 the connections list updates on its own once the install lands."
|
|
3377
3406
|
],
|
|
3378
3407
|
// Names where the link GOES rather than what it does: installing happens on
|
|
@@ -3386,6 +3415,29 @@ var shopify_default2 = {
|
|
|
3386
3415
|
// ONE STORE PER ORGANIZATION. Two Shopify stores on one org would give every
|
|
3387
3416
|
// attributed order two possible sources.
|
|
3388
3417
|
exclusive: true,
|
|
3418
|
+
// VENDOR-FACING EVENT IDENTITY, published so readers outside this package
|
|
3419
|
+
// (drawbridge-sync's usage queue, an operator checking the Dev Dashboard)
|
|
3420
|
+
// see the same handle the order hook mints into transactions and enqueues.
|
|
3421
|
+
events: {
|
|
3422
|
+
order: {
|
|
3423
|
+
handle: ORDER_EVENT_HANDLE,
|
|
3424
|
+
// THE SUBSCRIPTION THE APP MINTS FOR ITSELF (Billing API, not the
|
|
3425
|
+
// managed-pricing meter system): a $0 recurring line plus this usage
|
|
3426
|
+
// line, approved by the org owner at Shopify's confirmation screen.
|
|
3427
|
+
// `terms` is the merchant-visible consent copy; "up to" because the
|
|
3428
|
+
// actual rate is plan-derived (conversionRate) and must never exceed
|
|
3429
|
+
// what was approved. cappedAmount bounds one 30-day cycle's usage
|
|
3430
|
+
// charges — a record beyond it errors until the merchant raises it.
|
|
3431
|
+
// ponytail: $1,000 cap ≈ $66k attributed revenue/cycle at 1.5%; raise
|
|
3432
|
+
// via a re-approved subscription when a merchant outgrows it.
|
|
3433
|
+
pricing: {
|
|
3434
|
+
cappedAmount: 1e3,
|
|
3435
|
+
currency: "usd",
|
|
3436
|
+
name: "Drawbridge Orders",
|
|
3437
|
+
terms: "Up to 1.5% of revenue from orders attributed to Drawbridge campaigns"
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
},
|
|
3389
3441
|
feature: "organization:connection:shopify",
|
|
3390
3442
|
fields: [
|
|
3391
3443
|
{
|
|
@@ -3571,7 +3623,7 @@ var shopify_default2 = {
|
|
|
3571
3623
|
// for one purchase. The hook used to loop for this itself; describing
|
|
3572
3624
|
// the writes moved the retry to the queue, with the same guarantee.
|
|
3573
3625
|
order: async ({ connection: connection2, context }, { logger: logger2, mintId, read } = {}) => {
|
|
3574
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3626
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3575
3627
|
const {
|
|
3576
3628
|
advertisement,
|
|
3577
3629
|
created_at: createdAt,
|
|
@@ -3813,8 +3865,26 @@ var shopify_default2 = {
|
|
|
3813
3865
|
});
|
|
3814
3866
|
}
|
|
3815
3867
|
}
|
|
3816
|
-
const
|
|
3868
|
+
const billable = (org == null ? void 0 : org.billingProvider) === "shopify" && fee > 0 && !backfill;
|
|
3869
|
+
if (billable && !((_f = connection2 == null ? void 0 : connection2.source) == null ? void 0 : _f.id)) {
|
|
3870
|
+
(_g = logger2 == null ? void 0 : logger2.error) == null ? void 0 : _g.call(logger2, new Error(
|
|
3871
|
+
"shopify.usage.billing.skipped on order " + orderId + ": " + Math.round(fee * 100) + " cents not billed \u2014 connection " + (connection2 == null ? void 0 : connection2.id) + " has no source.id"
|
|
3872
|
+
), {
|
|
3873
|
+
extra: {
|
|
3874
|
+
connectionId: connection2 == null ? void 0 : connection2.id,
|
|
3875
|
+
fee,
|
|
3876
|
+
orderDocId,
|
|
3877
|
+
orderId: String(orderId)
|
|
3878
|
+
}
|
|
3879
|
+
});
|
|
3880
|
+
}
|
|
3881
|
+
const enqueues = billable && ((_h = connection2 == null ? void 0 : connection2.source) == null ? void 0 : _h.id) ? [{
|
|
3817
3882
|
data: {
|
|
3883
|
+
// The meter handle travels WITH the job so the sender can
|
|
3884
|
+
// verify it against the transaction prefix and refuse a
|
|
3885
|
+
// drifted pair — idempotency keys are permanent, so a
|
|
3886
|
+
// mistraceable event can never be resent under its own key.
|
|
3887
|
+
handle: ORDER_EVENT_HANDLE,
|
|
3818
3888
|
idempotencyKey: String(orderId),
|
|
3819
3889
|
orderDocId,
|
|
3820
3890
|
orderId: String(orderId),
|
|
@@ -3824,7 +3894,7 @@ var shopify_default2 = {
|
|
|
3824
3894
|
// here — the event handle plus the order id — and sent as the
|
|
3825
3895
|
// event's `reference`. queue/usage.js stamps the same id onto
|
|
3826
3896
|
// the order as billed.transaction.
|
|
3827
|
-
transaction: "
|
|
3897
|
+
transaction: ORDER_EVENT_HANDLE + "." + orderId,
|
|
3828
3898
|
value: Math.round(fee * 100)
|
|
3829
3899
|
},
|
|
3830
3900
|
name: "billing",
|
|
@@ -3967,7 +4037,8 @@ var shopify_default2 = {
|
|
|
3967
4037
|
// access token still works, reconciles the scopes the store granted
|
|
3968
4038
|
// against the ones the app now needs, and queues a webhook
|
|
3969
4039
|
// reconciliation.
|
|
3970
|
-
health: async ({ connection: connection2, workflow }, { adminToken, read, reconcileScopes, resolveSettings, rotateToken, shopify } = {}) => {
|
|
4040
|
+
health: async ({ connection: connection2, workflow }, { adminToken, logger: logger2, read, reconcileScopes, resolveSettings, rotateToken, shopify } = {}) => {
|
|
4041
|
+
var _a, _b;
|
|
3971
4042
|
const request2 = {
|
|
3972
4043
|
connectionId: workflow.connection,
|
|
3973
4044
|
organizationId: workflow.organization,
|
|
@@ -3986,7 +4057,50 @@ var shopify_default2 = {
|
|
|
3986
4057
|
}
|
|
3987
4058
|
await shopify.oauth.ping({ adminAccessToken, domain: connection2.shop });
|
|
3988
4059
|
const scopesMissing = await reconcileScopes({ shop: connection2.shop });
|
|
4060
|
+
const writes = [];
|
|
4061
|
+
let source = connection2.source || null;
|
|
4062
|
+
let sourceRepaired = false;
|
|
4063
|
+
let metered = (source == null ? void 0 : source.metered) ?? null;
|
|
4064
|
+
let shopCurrency = null;
|
|
4065
|
+
let billingProbeFailed = false;
|
|
4066
|
+
try {
|
|
4067
|
+
if (!(source == null ? void 0 : source.id)) {
|
|
4068
|
+
const shopData = await shopify.oauth.getShop({ adminAccessToken, shop: connection2.shop });
|
|
4069
|
+
source = {
|
|
4070
|
+
domain: shopData.myshopifyDomain,
|
|
4071
|
+
id: String(shopData.id),
|
|
4072
|
+
label: shopData.name
|
|
4073
|
+
};
|
|
4074
|
+
shopCurrency = String(shopData.currency || "").toLowerCase() || null;
|
|
4075
|
+
sourceRepaired = true;
|
|
4076
|
+
}
|
|
4077
|
+
const { subscriptions } = await shopify.admin.getActiveAppSubscriptions({
|
|
4078
|
+
adminAccessToken,
|
|
4079
|
+
domain: connection2.shop
|
|
4080
|
+
});
|
|
4081
|
+
if (subscriptions.length && subscriptions.every((subscription) => typeof subscription.metered === "boolean")) {
|
|
4082
|
+
metered = subscriptions.some((subscription) => subscription.metered);
|
|
4083
|
+
}
|
|
4084
|
+
} catch (probeError) {
|
|
4085
|
+
billingProbeFailed = true;
|
|
4086
|
+
(_a = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _a.call(logger2, "shopify.health.billing.probe.failed", {
|
|
4087
|
+
connectionId: connection2.id,
|
|
4088
|
+
message: probeError == null ? void 0 : probeError.message,
|
|
4089
|
+
shop: connection2.shop
|
|
4090
|
+
});
|
|
4091
|
+
}
|
|
4092
|
+
if (sourceRepaired || metered !== null && metered !== (((_b = connection2.source) == null ? void 0 : _b.metered) ?? null)) {
|
|
4093
|
+
writes.push({
|
|
4094
|
+
collection: "connection",
|
|
4095
|
+
data: {
|
|
4096
|
+
$set: sourceRepaired ? { source: { ...source, ...metered !== null && { metered } } } : { "source.metered": metered }
|
|
4097
|
+
},
|
|
4098
|
+
operation: "update",
|
|
4099
|
+
query: { id: connection2.id }
|
|
4100
|
+
});
|
|
4101
|
+
}
|
|
3989
4102
|
return {
|
|
4103
|
+
writes,
|
|
3990
4104
|
enqueues: [{
|
|
3991
4105
|
data: {
|
|
3992
4106
|
data: {
|
|
@@ -3999,13 +4113,19 @@ var shopify_default2 = {
|
|
|
3999
4113
|
options: { jobId: "connection.update.register." + workflow.connection + "." + randomUUID() },
|
|
4000
4114
|
queue: "connection"
|
|
4001
4115
|
}],
|
|
4002
|
-
message: (scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.",
|
|
4116
|
+
message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === false ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
|
|
4003
4117
|
request: request2,
|
|
4004
4118
|
response: {
|
|
4119
|
+
billingProbeFailed,
|
|
4120
|
+
metered,
|
|
4005
4121
|
pingedAt: /* @__PURE__ */ new Date(),
|
|
4006
4122
|
refreshTokenExpiresAt: refreshTokenExpiresAt || null,
|
|
4007
4123
|
refreshTokenRotated,
|
|
4008
4124
|
scopesMissing,
|
|
4125
|
+
// The live settlement currency, for an operator — never
|
|
4126
|
+
// written, see above.
|
|
4127
|
+
...shopCurrency && { shopCurrency },
|
|
4128
|
+
sourceRepaired,
|
|
4009
4129
|
webhookReconciliationQueued: true
|
|
4010
4130
|
}
|
|
4011
4131
|
};
|
|
@@ -4273,12 +4393,35 @@ var shopify_default2 = {
|
|
|
4273
4393
|
//
|
|
4274
4394
|
// Scope drift is NOT here: drawbridge-sync writes it onto the connection
|
|
4275
4395
|
// document, and the document's own warnings render beside these.
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4396
|
+
// Both cards carry `action : 'billing'`: the dashboard renders it as a real
|
|
4397
|
+
// button that mints the corrective subscription (POST .../billing) and sends
|
|
4398
|
+
// the owner to Shopify's confirmation screen — the fix lives in OUR
|
|
4399
|
+
// dashboard, and the one Shopify-hosted step is the charge consent no app
|
|
4400
|
+
// can perform for a merchant.
|
|
4401
|
+
tasks: (data2) => {
|
|
4402
|
+
var _a;
|
|
4403
|
+
return [
|
|
4404
|
+
...(data2 == null ? void 0 : data2.status) === "pending" ? [
|
|
4405
|
+
{
|
|
4406
|
+
action: "billing",
|
|
4407
|
+
message: "Approve the Drawbridge plan to activate this connection. You'll confirm the pricing on Shopify, then everything else happens here.",
|
|
4408
|
+
title: "Approve your plan"
|
|
4409
|
+
}
|
|
4410
|
+
] : [],
|
|
4411
|
+
// The store's ACTIVE approval carries no usage component — stamped by
|
|
4412
|
+
// the daily health check and the approval webhook (`source.metered`).
|
|
4413
|
+
// Approved pricing is never retroactive, so the fix is a fresh approval.
|
|
4414
|
+
// Gated on an EXPLICIT false — a connection the probe hasn't reached
|
|
4415
|
+
// (or couldn't read) shows nothing rather than nagging on silence.
|
|
4416
|
+
...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === false ? [
|
|
4417
|
+
{
|
|
4418
|
+
action: "billing",
|
|
4419
|
+
message: "Order billing isn't set up for this store, so campaign-attributed orders aren't being charged. Approve the updated plan to fix it \u2014 one click here, one confirmation on Shopify.",
|
|
4420
|
+
title: "Fix order billing"
|
|
4421
|
+
}
|
|
4422
|
+
] : []
|
|
4423
|
+
];
|
|
4424
|
+
},
|
|
4282
4425
|
title: "Shopify"
|
|
4283
4426
|
};
|
|
4284
4427
|
|
|
@@ -4452,6 +4595,9 @@ var webhook_default = {
|
|
|
4452
4595
|
// Nothing to be exclusive with — there is no second webhook vendor, and a
|
|
4453
4596
|
// merchant with two endpoints is a step-level choice rather than a second
|
|
4454
4597
|
// connection.
|
|
4598
|
+
// No vendor-facing event identities — declared empty so the contract stays
|
|
4599
|
+
// explicit: a vendor that gains one adds it here, never as a side channel.
|
|
4600
|
+
events: {},
|
|
4455
4601
|
exclusive: false,
|
|
4456
4602
|
feature: "organization:connection:webhook",
|
|
4457
4603
|
fields: [
|
|
@@ -4743,16 +4889,16 @@ var connections = Object.freeze({
|
|
|
4743
4889
|
(() => {
|
|
4744
4890
|
var _a;
|
|
4745
4891
|
const routes = {};
|
|
4746
|
-
for (const [
|
|
4892
|
+
for (const [slug2, manifest] of Object.entries(connections)) {
|
|
4747
4893
|
for (const [name, step] of leaves(manifest.steps)) {
|
|
4748
4894
|
const type = "step." + name;
|
|
4749
4895
|
const queue = (_a = step({})) == null ? void 0 : _a.queue;
|
|
4750
4896
|
if (routes[type] && routes[type].queue !== queue) {
|
|
4751
4897
|
throw new Error(
|
|
4752
|
-
"Step " + type + " routes to " + routes[type].queue + " for " + routes[type].slug + " and " + queue + " for " +
|
|
4898
|
+
"Step " + type + " routes to " + routes[type].queue + " for " + routes[type].slug + " and " + queue + " for " + slug2 + " \u2014 one of them would be enqueued nowhere"
|
|
4753
4899
|
);
|
|
4754
4900
|
}
|
|
4755
|
-
routes[type] = { queue, slug };
|
|
4901
|
+
routes[type] = { queue, slug: slug2 };
|
|
4756
4902
|
}
|
|
4757
4903
|
}
|
|
4758
4904
|
})();
|
|
@@ -4765,21 +4911,21 @@ var catalogConnections = (env = {}) => Object.fromEntries(
|
|
|
4765
4911
|
Object.entries(availableConnections(env)).filter(([, manifest]) => !manifest.private)
|
|
4766
4912
|
);
|
|
4767
4913
|
var publicSettingsBySlug = Object.fromEntries(
|
|
4768
|
-
Object.entries(connections).map(([
|
|
4769
|
-
|
|
4914
|
+
Object.entries(connections).map(([slug2, manifest]) => [
|
|
4915
|
+
slug2,
|
|
4770
4916
|
manifest.fields.filter((field2) => !field2.redact).map((field2) => field2.key)
|
|
4771
4917
|
])
|
|
4772
4918
|
);
|
|
4773
4919
|
var connectionSteps = (env = {}) => Object.entries(availableConnections(env)).flatMap(
|
|
4774
|
-
([
|
|
4920
|
+
([slug2, manifest]) => leaves(manifest.steps).map(([name, step]) => ({ ...step({}), slug: slug2, type: "step." + name }))
|
|
4775
4921
|
);
|
|
4776
4922
|
var hookSupport = (name) => ({
|
|
4777
|
-
no: Object.keys(connections).filter((
|
|
4778
|
-
yes: Object.keys(connections).filter((
|
|
4923
|
+
no: Object.keys(connections).filter((slug2) => !implemented(connections[slug2].hooks, name)),
|
|
4924
|
+
yes: Object.keys(connections).filter((slug2) => implemented(connections[slug2].hooks, name))
|
|
4779
4925
|
});
|
|
4780
|
-
var connectFields = (
|
|
4926
|
+
var connectFields = (slug2) => {
|
|
4781
4927
|
var _a;
|
|
4782
|
-
return (((_a = connections[
|
|
4928
|
+
return (((_a = connections[slug2]) == null ? void 0 : _a.fields) || []).map(({ copy, from, hook, input, key, label, message, options, placeholder, redact, required, search }) => ({
|
|
4783
4929
|
...copy && { copy: true },
|
|
4784
4930
|
...hook && { hook },
|
|
4785
4931
|
...from && { from },
|
|
@@ -4799,18 +4945,18 @@ var connectFields = (slug) => {
|
|
|
4799
4945
|
secret: Boolean(redact)
|
|
4800
4946
|
}));
|
|
4801
4947
|
};
|
|
4802
|
-
var runHook = async (
|
|
4803
|
-
const manifest = connections[
|
|
4804
|
-
if (!manifest) return { outcome: OUTCOMES.unsupported, reason: "no such connection: " +
|
|
4948
|
+
var runHook = async (slug2, name, props = {}, options = {}) => {
|
|
4949
|
+
const manifest = connections[slug2];
|
|
4950
|
+
if (!manifest) return { outcome: OUTCOMES.unsupported, reason: "no such connection: " + slug2 };
|
|
4805
4951
|
const hook = name.split(".").reduce(
|
|
4806
4952
|
(node, key) => node && typeof node === "object" && Object.hasOwn(node, key) ? node[key] : void 0,
|
|
4807
4953
|
manifest.hooks
|
|
4808
4954
|
);
|
|
4809
4955
|
if (hook === false || hook == null) {
|
|
4810
|
-
return { outcome: OUTCOMES.unsupported, reason:
|
|
4956
|
+
return { outcome: OUTCOMES.unsupported, reason: slug2 + " does not implement " + name };
|
|
4811
4957
|
}
|
|
4812
4958
|
if (typeof hook !== "function") {
|
|
4813
|
-
return { outcome: OUTCOMES.unimplemented, reason:
|
|
4959
|
+
return { outcome: OUTCOMES.unimplemented, reason: slug2 + " implements " + name + " outside this package" };
|
|
4814
4960
|
}
|
|
4815
4961
|
try {
|
|
4816
4962
|
const result = await hook({ ...props, manifest }, options);
|
|
@@ -4845,9 +4991,9 @@ var mergeSettings = ({ existing, incoming }) => {
|
|
|
4845
4991
|
;
|
|
4846
4992
|
return merged;
|
|
4847
4993
|
};
|
|
4848
|
-
var redactSettings = ({ slug, settings }) => {
|
|
4994
|
+
var redactSettings = ({ slug: slug2, settings }) => {
|
|
4849
4995
|
if (!settings || typeof settings !== "object") return settings;
|
|
4850
|
-
const allowed = publicSettingsBySlug[
|
|
4996
|
+
const allowed = publicSettingsBySlug[slug2] || [];
|
|
4851
4997
|
return Object.fromEntries(
|
|
4852
4998
|
Object.entries(settings).filter(([key]) => allowed.includes(key))
|
|
4853
4999
|
);
|