canada-api 2.0.4 → 3.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.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 National Defence
3
+ Copyright (c) His Majesty the King in Right of Canada, as represented by the Minister of National Defence, 2022.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -4,51 +4,61 @@
4
4
 
5
5
  Cross platform API for fetching public data from [canada.ca](https://www.canada.ca).
6
6
 
7
- ## Install
8
- ### Browsers
9
7
 
8
+ ## Browser
10
9
  ```html
11
- <script src="https://cdn.jsdelivr.net/npm/canada-api@2.0.4"></script>
12
- <script>
13
- ca.meta("en/department-national-defence").then(meta => {
14
- console.log(meta)
15
- })
16
- </script>
10
+ <script src="https://cdn.jsdelivr.net/npm/canada-api@3.0.0"></script>
17
11
  ```
18
12
 
19
- ### Nodejs
13
+ ## Node 10+
20
14
 
21
- ```javascript
22
- const ca = require("canada-api")
23
- ca.meta("en/department-national-defence")
15
+ ### Install
16
+
17
+ ```shell
18
+ npm install canada-api
24
19
  ```
25
20
 
21
+ ### Usage
26
22
 
23
+ ```js
24
+ const ca = require('canada-api')
25
+ ```
27
26
 
28
27
  ## Core API
29
28
 
30
- ### `ca.fetch(url[, options])`
29
+ ### `ca.request(url)`
31
30
 
32
- - `url` {string|URL} absolute URL
33
- - `options` {Object} fetch [options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) (Some limitations based on implementation)
34
- - `jobOptions` {Object} rate limiter [job options](https://github.com/SGrondin/bottleneck#job-options)
35
- - Returns: {Promise} Fulfills with {Response} upon success
31
+ - `url` {string|URL} relative or absolute URL on [canada.ca](https://www.canada.ca)
32
+ - Returns: {Promise} Fulfills with {Object} upon success
36
33
 
37
- Uses [cross-fetch](https://github.com/lquixada/cross-fetch#readme) for a universal [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation. Calls are rate limited to avoid hitting request limits that result in throttling. Throws an {Error} if the request does not complete successfully or if the destination URL is not on [canada.ca](https://www.canada.ca).
34
+ Throws {Error} if the request does not complete successfully or if the destination URL is not on [canada.ca](https://www.canada.ca).
38
35
 
36
+ The properties included on each object:
37
+ - `url` {string} destination URL
38
+ - `redirected` {boolean} If the destination path is different from the request
39
+ - `data` {string|Object} Document content as string or json data
40
+
41
+ ```json
42
+ {
43
+ "url": "https://www.canada.ca/en/department-national-defence.html",
44
+ "redirected": false,
45
+ "data": "<!DOCTYPE html>\r\n...."
46
+ }
47
+ ```
39
48
 
40
- ### `ca.fetch.limiter`
49
+
50
+ ### `ca.request.limiter`
41
51
 
42
52
  - {Bottleneck}
43
53
 
44
- The [Rate limiter](https://github.com/SGrondin/bottleneck#readme) used in `ca.fetch()`.
54
+ The [Rate limiter](https://github.com/SGrondin/bottleneck#readme) used in `ca.request()`.
45
55
 
46
56
 
47
57
  ### `ca.normalize(url[, type])`
48
58
 
49
59
  - `url` {string|URL} node URL
50
60
  - `type` {string} Possible values `'path'`, `'children'`, `'content'` or `'meta'`. **Default**: `'path'`
51
- - Returns: {string} Normalized path or URL
61
+ - Returns: {URL} Normalized URL
52
62
 
53
63
  Validates and formats [canada.ca](https://www.canada.ca) URLs based on type. URLs can take many forms, so not all options will be valid. Throws an {Error} if the URL is invalid, or the type requested is not possible.
54
64
 
@@ -63,42 +73,89 @@ Base URL used for resolving relative URLs as well as URL validation. Value is `'
63
73
 
64
74
  ## Basic API
65
75
 
66
- ### `ca.children(url[, options])`
76
+ ### `ca.children(url)`
67
77
 
68
78
  - `url` {string|URL} absolute or relative URL
69
- - `options` {Object} fetch [options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)
70
- - `jobOptions` {Object} rate limiter [job options](https://github.com/SGrondin/bottleneck#job-options)
71
- - `rawContent` {boolean} Fulfills with unmodified {string} **Default:** `false`
72
- - Returns: {Promise} Fulfills with {Object[]} of child nodes
79
+ - Returns: {Promise} Fulfills with {Object} containing child nodes
73
80
 
74
81
  Parses sitemaps to get a list of child nodes.
75
82
 
83
+ ```json
84
+ {
85
+ "url": "https://www.canada.ca/en/department-national-defence.sitemap.xml",
86
+ "redirected": false,
87
+ "data": [
88
+ {
89
+ "url": "https://www.canada.ca/en/department-national-defence/...",
90
+ "lastmod": "2022-09-20T00:00:00.000Z"
91
+ },
92
+ ]
93
+ }
94
+ ```
95
+
96
+ Getting children of DAM folders/assets is not available.
76
97
 
77
- ### `ca.content(url[, options])`
98
+ ### `ca.content(url)`
78
99
 
79
100
  - `url` {string|URL} absolute or relative URL
80
- - `options` {Object} fetch [options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)
81
- - `jobOptions` {Object} rate limiter [job options](https://github.com/SGrondin/bottleneck#job-options)
82
- - `rawContent` {boolean} Fulfills with unmodified {string} **Default:** `false`
83
- - Returns: {Promise} Fulfills with {string|Object}
101
+ - Returns: {Promise} Fulfills with {Object} containing document contents
84
102
 
85
- Retrieves the document contents. The result depends on the `content-type` header of {Response}:
86
- - `'application/json'` parses response and fulfills with {Object}
87
- - `'text/html'` compresses whitespace and fulfills with {string}
88
- - Other types are fulfilled as {string} with no modification
103
+ Retrieves the document contents.
89
104
 
105
+ The properties included on each object:
106
+ ```json
107
+ {
108
+ "url": "https://www.canada.ca/en/department-national-defence.html",
109
+ "redirected": false,
110
+ "data": "<!DOCTYPE html>\r\n...."
111
+ }
112
+ ```
90
113
 
91
- ### `ca.meta(url[, options])`
114
+ Can also be used for DAM assets:
92
115
 
93
- - `url` {string|URL} absolute or relative URL
94
- - `options` {Object} fetch [options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)
95
- - `jobOptions` {Object} rate limiter [job options](https://github.com/SGrondin/bottleneck#job-options)
96
- - `rawContent` {boolean} Fulfills with unmodified {string} **Default:** `false`
97
- - Returns: {Promise} Fulfills with {Object} with metadata properties
116
+ ```json
117
+ {
118
+ "url": "https://www.canada.ca/content/dam/dnd-mdn/documents/json/maple-en.json",
119
+ "redirected": false,
120
+ "data": {
121
+ "data": []
122
+ }
123
+ }
124
+ ```
98
125
 
99
- Nodes contain a variety of metadata properties that can be accessed through a public API. Some properties are reformatted for consistency if `rawContent` option is `false`. A separate document will be created as a reference for the most useful ones.
126
+ ### `ca.meta(url)`
100
127
 
128
+ - `url` {string|URL} absolute or relative URL
129
+ - Returns: {Promise} Fulfills with {Object} containing metadata properties
130
+
131
+ Nodes contain a variety of metadata properties that can be accessed through a public API. Some properties such as date formats are reformatted for consistency.
132
+
133
+ The properties included on each object:
134
+ ```json
135
+ {
136
+ "url": "https://www.canada.ca/en/department-national-defence/_jcr_content.json",
137
+ "redirected": false,
138
+ "data": {
139
+ "cq:lastModified": "2022-10-25T19:16:28.000Z",
140
+ "fluidWidth": false,
141
+ }
142
+ }
143
+ ```
144
+
145
+ Can also be used for DAM assets:
146
+
147
+ ```json
148
+ {
149
+ "url": "https://www.canada.ca/content/dam/dnd-mdn/documents/json/maple-en.json/_jcr_content.json",
150
+ "redirected": false,
151
+ "data": {
152
+ "dam:assetState": "processed",
153
+ "jcr:lastModified": "2022-10-26T19:39:54.000Z",
154
+ "jcr:primaryType": "dam:AssetContent"
155
+ }
156
+ }
157
+ ```
101
158
 
102
159
  ## Extended API
103
160
 
104
- TBD
161
+ TBD
package/dist/ca.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("cross-fetch")):"function"==typeof define&&define.amd?define("ca",["cross-fetch"],e):"object"==typeof exports?exports.ca=e(require("cross-fetch")):t.ca=e(t.fetch)}("undefined"!=typeof self?self:this,(t=>(()=>{var e={209:function(t,e,s){t.exports=function(){"use strict";var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==s.g?s.g:"undefined"!=typeof self?self:{};var e,r,i={load:function(t,e,s={}){var r,i,n;for(r in e)n=e[r],s[r]=null!=(i=t[r])?i:n;return s},overwrite:function(t,e,s={}){var r,i;for(r in t)i=t[r],void 0!==e[r]&&(s[r]=i);return s}},n=class{constructor(t,e){this.incr=t,this.decr=e,this._first=null,this._last=null,this.length=0}push(t){var e;this.length++,"function"==typeof this.incr&&this.incr(),e={value:t,prev:this._last,next:null},null!=this._last?(this._last.next=e,this._last=e):this._first=this._last=e}shift(){var t;if(null!=this._first)return this.length--,"function"==typeof this.decr&&this.decr(),t=this._first.value,null!=(this._first=this._first.next)?this._first.prev=null:this._last=null,t}first(){if(null!=this._first)return this._first.value}getArray(){var t,e,s;for(t=this._first,s=[];null!=t;)s.push((e=t,t=t.next,e.value));return s}forEachShift(t){var e;for(e=this.shift();null!=e;)t(e),e=this.shift()}debug(){var t,e,s,r,i;for(t=this._first,i=[];null!=t;)i.push((e=t,t=t.next,{value:e.value,prev:null!=(s=e.prev)?s.value:void 0,next:null!=(r=e.next)?r.value:void 0}));return i}},o=class{constructor(t){if(this.instance=t,this._events={},null!=this.instance.on||null!=this.instance.once||null!=this.instance.removeAllListeners)throw new Error("An Emitter already exists for this object");this.instance.on=(t,e)=>this._addListener(t,"many",e),this.instance.once=(t,e)=>this._addListener(t,"once",e),this.instance.removeAllListeners=(t=null)=>null!=t?delete this._events[t]:this._events={}}_addListener(t,e,s){var r;return null==(r=this._events)[t]&&(r[t]=[]),this._events[t].push({cb:s,status:e}),this.instance}listenerCount(t){return null!=this._events[t]?this._events[t].length:0}async trigger(t,...e){var s,r;try{if("debug"!==t&&this.trigger("debug",`Event triggered: ${t}`,e),null==this._events[t])return;return this._events[t]=this._events[t].filter((function(t){return"none"!==t.status})),r=this._events[t].map((async t=>{var s,r;if("none"!==t.status){"once"===t.status&&(t.status="none");try{return"function"==typeof(null!=(r="function"==typeof t.cb?t.cb(...e):void 0)?r.then:void 0)?await r:r}catch(t){return s=t,this.trigger("error",s),null}}})),(await Promise.all(r)).find((function(t){return null!=t}))}catch(t){return s=t,this.trigger("error",s),null}}};e=n,r=o;var a,h,u=class extends Error{};h=i,a=u;var l,c,p=class{constructor(t,e,s,r,i,n,o,a){this.task=t,this.args=e,this.rejectOnDrop=i,this.Events=n,this._states=o,this.Promise=a,this.options=h.load(s,r),this.options.priority=this._sanitizePriority(this.options.priority),this.options.id===r.id&&(this.options.id=`${this.options.id}-${this._randomIndex()}`),this.promise=new this.Promise(((t,e)=>{this._resolve=t,this._reject=e})),this.retryCount=0}_sanitizePriority(t){var e;return(e=~~t!==t?5:t)<0?0:e>9?9:e}_randomIndex(){return Math.random().toString(36).slice(2)}doDrop({error:t,message:e="This job has been dropped by Bottleneck"}={}){return!!this._states.remove(this.options.id)&&(this.rejectOnDrop&&this._reject(null!=t?t:new a(e)),this.Events.trigger("dropped",{args:this.args,options:this.options,task:this.task,promise:this.promise}),!0)}_assertStatus(t){var e;if((e=this._states.jobStatus(this.options.id))!==t&&("DONE"!==t||null!==e))throw new a(`Invalid job status ${e}, expected ${t}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`)}doReceive(){return this._states.start(this.options.id),this.Events.trigger("received",{args:this.args,options:this.options})}doQueue(t,e){return this._assertStatus("RECEIVED"),this._states.next(this.options.id),this.Events.trigger("queued",{args:this.args,options:this.options,reachedHWM:t,blocked:e})}doRun(){return 0===this.retryCount?(this._assertStatus("QUEUED"),this._states.next(this.options.id)):this._assertStatus("EXECUTING"),this.Events.trigger("scheduled",{args:this.args,options:this.options})}async doExecute(t,e,s,r){var i,n,o;0===this.retryCount?(this._assertStatus("RUNNING"),this._states.next(this.options.id)):this._assertStatus("EXECUTING"),n={args:this.args,options:this.options,retryCount:this.retryCount},this.Events.trigger("executing",n);try{if(o=await(null!=t?t.schedule(this.options,this.task,...this.args):this.task(...this.args)),e())return this.doDone(n),await r(this.options,n),this._assertStatus("DONE"),this._resolve(o)}catch(t){return i=t,this._onFailure(i,n,e,s,r)}}doExpire(t,e,s){var r,i;return this._states.jobStatus("RUNNING"===this.options.id)&&this._states.next(this.options.id),this._assertStatus("EXECUTING"),i={args:this.args,options:this.options,retryCount:this.retryCount},r=new a(`This job timed out after ${this.options.expiration} ms.`),this._onFailure(r,i,t,e,s)}async _onFailure(t,e,s,r,i){var n,o;if(s())return null!=(n=await this.Events.trigger("failed",t,e))?(o=~~n,this.Events.trigger("retry",`Retrying ${this.options.id} after ${o} ms`,e),this.retryCount++,r(o)):(this.doDone(e),await i(this.options,e),this._assertStatus("DONE"),this._reject(t))}doDone(t){return this._assertStatus("EXECUTING"),this._states.next(this.options.id),this.Events.trigger("done",t)}};c=i,l=u;var d;d=u;var _;_=n;var f,v,m,g,y,w="2.19.5",b={version:w},E=Object.freeze({version:w,default:b}),O=()=>console.log("You must import the full version of Bottleneck in order to use this feature."),j=()=>console.log("You must import the full version of Bottleneck in order to use this feature.");y=i,f=o,m=O,v=j,g=()=>console.log("You must import the full version of Bottleneck in order to use this feature.");var x,k,R=function(){class t{constructor(t={}){this.deleteKey=this.deleteKey.bind(this),this.limiterOptions=t,y.load(this.limiterOptions,this.defaults,this),this.Events=new f(this),this.instances={},this.Bottleneck=U,this._startAutoCleanup(),this.sharedConnection=null!=this.connection,null==this.connection&&("redis"===this.limiterOptions.datastore?this.connection=new m(Object.assign({},this.limiterOptions,{Events:this.Events})):"ioredis"===this.limiterOptions.datastore&&(this.connection=new v(Object.assign({},this.limiterOptions,{Events:this.Events}))))}key(t=""){var e;return null!=(e=this.instances[t])?e:(()=>{var e;return e=this.instances[t]=new this.Bottleneck(Object.assign(this.limiterOptions,{id:`${this.id}-${t}`,timeout:this.timeout,connection:this.connection})),this.Events.trigger("created",e,t),e})()}async deleteKey(t=""){var e,s;return s=this.instances[t],this.connection&&(e=await this.connection.__runCommand__(["del",...g.allKeys(`${this.id}-${t}`)])),null!=s&&(delete this.instances[t],await s.disconnect()),null!=s||e>0}limiters(){var t,e,s,r;for(t in s=[],e=this.instances)r=e[t],s.push({key:t,limiter:r});return s}keys(){return Object.keys(this.instances)}async clusterKeys(){var t,e,s,r,i,n,o,a,h;if(null==this.connection)return this.Promise.resolve(this.keys());for(n=[],t=null,h=`b_${this.id}-`.length,e="_settings".length;0!==t;)for([a,s]=await this.connection.__runCommand__(["scan",null!=t?t:0,"match",`b_${this.id}-*_settings`,"count",1e4]),t=~~a,r=0,o=s.length;r<o;r++)i=s[r],n.push(i.slice(h,-e));return n}_startAutoCleanup(){var t;return clearInterval(this.interval),"function"==typeof(t=this.interval=setInterval((async()=>{var t,e,s,r,i,n;for(e in i=Date.now(),r=[],s=this.instances){n=s[e];try{await n._store.__groupCheck__(i)?r.push(this.deleteKey(e)):r.push(void 0)}catch(e){t=e,r.push(n.Events.trigger("error",t))}}return r}),this.timeout/2)).unref?t.unref():void 0}updateSettings(t={}){if(y.overwrite(t,this.defaults,this),y.overwrite(t,t,this.limiterOptions),null!=t.timeout)return this._startAutoCleanup()}disconnect(t=!0){var e;if(!this.sharedConnection)return null!=(e=this.connection)?e.disconnect(t):void 0}}return t.prototype.defaults={timeout:3e5,connection:null,Promise,id:"group-key"},t}.call(t);k=i,x=o;var C,I,D,P,T,A,L,S,q,$=function(){class t{constructor(t={}){this.options=t,k.load(this.options,this.defaults,this),this.Events=new x(this),this._arr=[],this._resetPromise(),this._lastFlush=Date.now()}_resetPromise(){return this._promise=new this.Promise(((t,e)=>this._resolve=t))}_flush(){return clearTimeout(this._timeout),this._lastFlush=Date.now(),this._resolve(),this.Events.trigger("batch",this._arr),this._arr=[],this._resetPromise()}add(t){var e;return this._arr.push(t),e=this._promise,this._arr.length===this.maxSize?this._flush():null!=this.maxTime&&1===this._arr.length&&(this._timeout=setTimeout((()=>this._flush()),this.maxTime)),e}}return t.prototype.defaults={maxTime:null,maxSize:null,Promise},t}.call(t),B=(q=E)&&q.default||q,N=[].splice;S=i,P=class{constructor(t){this.Events=new r(this),this._length=0,this._lists=function(){var s,r,i;for(i=[],s=1,r=t;1<=r?s<=r:s>=r;1<=r?++s:--s)i.push(new e((()=>this.incr()),(()=>this.decr())));return i}.call(this)}incr(){if(0==this._length++)return this.Events.trigger("leftzero")}decr(){if(0==--this._length)return this.Events.trigger("zero")}push(t){return this._lists[t.options.priority].push(t)}queued(t){return null!=t?this._lists[t].length:this._length}shiftAll(t){return this._lists.forEach((function(e){return e.forEachShift(t)}))}getFirst(t=this._lists){var e,s,r;for(e=0,s=t.length;e<s;e++)if((r=t[e]).length>0)return r;return[]}shiftLastFrom(t){return this.getFirst(this._lists.slice(t).reverse()).shift()}},I=p,D=class{constructor(t,e,s){this.instance=t,this.storeOptions=e,this.clientId=this.instance._randomIndex(),c.load(s,s,this),this._nextRequest=this._lastReservoirRefresh=this._lastReservoirIncrease=Date.now(),this._running=0,this._done=0,this._unblockTime=0,this.ready=this.Promise.resolve(),this.clients={},this._startHeartbeat()}_startHeartbeat(){var t;return null==this.heartbeat&&(null!=this.storeOptions.reservoirRefreshInterval&&null!=this.storeOptions.reservoirRefreshAmount||null!=this.storeOptions.reservoirIncreaseInterval&&null!=this.storeOptions.reservoirIncreaseAmount)?"function"==typeof(t=this.heartbeat=setInterval((()=>{var t,e,s,r,i;if(r=Date.now(),null!=this.storeOptions.reservoirRefreshInterval&&r>=this._lastReservoirRefresh+this.storeOptions.reservoirRefreshInterval&&(this._lastReservoirRefresh=r,this.storeOptions.reservoir=this.storeOptions.reservoirRefreshAmount,this.instance._drainAll(this.computeCapacity())),null!=this.storeOptions.reservoirIncreaseInterval&&r>=this._lastReservoirIncrease+this.storeOptions.reservoirIncreaseInterval&&(({reservoirIncreaseAmount:t,reservoirIncreaseMaximum:s,reservoir:i}=this.storeOptions),this._lastReservoirIncrease=r,(e=null!=s?Math.min(t,s-i):t)>0))return this.storeOptions.reservoir+=e,this.instance._drainAll(this.computeCapacity())}),this.heartbeatInterval)).unref?t.unref():void 0:clearInterval(this.heartbeat)}async __publish__(t){return await this.yieldLoop(),this.instance.Events.trigger("message",t.toString())}async __disconnect__(t){return await this.yieldLoop(),clearInterval(this.heartbeat),this.Promise.resolve()}yieldLoop(t=0){return new this.Promise((function(e,s){return setTimeout(e,t)}))}computePenalty(){var t;return null!=(t=this.storeOptions.penalty)?t:15*this.storeOptions.minTime||5e3}async __updateSettings__(t){return await this.yieldLoop(),c.overwrite(t,t,this.storeOptions),this._startHeartbeat(),this.instance._drainAll(this.computeCapacity()),!0}async __running__(){return await this.yieldLoop(),this._running}async __queued__(){return await this.yieldLoop(),this.instance.queued()}async __done__(){return await this.yieldLoop(),this._done}async __groupCheck__(t){return await this.yieldLoop(),this._nextRequest+this.timeout<t}computeCapacity(){var t,e;return({maxConcurrent:t,reservoir:e}=this.storeOptions),null!=t&&null!=e?Math.min(t-this._running,e):null!=t?t-this._running:null!=e?e:null}conditionsCheck(t){var e;return null==(e=this.computeCapacity())||t<=e}async __incrementReservoir__(t){var e;return await this.yieldLoop(),e=this.storeOptions.reservoir+=t,this.instance._drainAll(this.computeCapacity()),e}async __currentReservoir__(){return await this.yieldLoop(),this.storeOptions.reservoir}isBlocked(t){return this._unblockTime>=t}check(t,e){return this.conditionsCheck(t)&&this._nextRequest-e<=0}async __check__(t){var e;return await this.yieldLoop(),e=Date.now(),this.check(t,e)}async __register__(t,e,s){var r,i;return await this.yieldLoop(),r=Date.now(),this.conditionsCheck(e)?(this._running+=e,null!=this.storeOptions.reservoir&&(this.storeOptions.reservoir-=e),i=Math.max(this._nextRequest-r,0),this._nextRequest=r+i+this.storeOptions.minTime,{success:!0,wait:i,reservoir:this.storeOptions.reservoir}):{success:!1}}strategyIsBlock(){return 3===this.storeOptions.strategy}async __submit__(t,e){var s,r,i;if(await this.yieldLoop(),null!=this.storeOptions.maxConcurrent&&e>this.storeOptions.maxConcurrent)throw new l(`Impossible to add a job having a weight of ${e} to a limiter having a maxConcurrent setting of ${this.storeOptions.maxConcurrent}`);return r=Date.now(),i=null!=this.storeOptions.highWater&&t===this.storeOptions.highWater&&!this.check(e,r),(s=this.strategyIsBlock()&&(i||this.isBlocked(r)))&&(this._unblockTime=r+this.computePenalty(),this._nextRequest=this._unblockTime+this.storeOptions.minTime,this.instance._dropAllQueued()),{reachedHWM:i,blocked:s,strategy:this.storeOptions.strategy}}async __free__(t,e){return await this.yieldLoop(),this._running-=e,this._done+=e,this.instance._drainAll(this.computeCapacity()),{running:this._running}}},T=()=>console.log("You must import the full version of Bottleneck in order to use this feature."),C=o,A=class{constructor(t){this.status=t,this._jobs={},this.counts=this.status.map((function(){return 0}))}next(t){var e,s;return s=(e=this._jobs[t])+1,null!=e&&s<this.status.length?(this.counts[e]--,this.counts[s]++,this._jobs[t]++):null!=e?(this.counts[e]--,delete this._jobs[t]):void 0}start(t){return 0,this._jobs[t]=0,this.counts[0]++}remove(t){var e;return null!=(e=this._jobs[t])&&(this.counts[e]--,delete this._jobs[t]),null!=e}jobStatus(t){var e;return null!=(e=this.status[this._jobs[t]])?e:null}statusJobs(t){var e,s,r,i;if(null!=t){if((s=this.status.indexOf(t))<0)throw new d(`status must be one of ${this.status.join(", ")}`);for(e in i=[],r=this._jobs)r[e]===s&&i.push(e);return i}return Object.keys(this._jobs)}statusCounts(){return this.counts.reduce(((t,e,s)=>(t[this.status[s]]=e,t)),{})}},L=class{constructor(t,e){this.schedule=this.schedule.bind(this),this.name=t,this.Promise=e,this._running=0,this._queue=new _}isEmpty(){return 0===this._queue.length}async _tryToRun(){var t,e,s,r,i,n,o;if(this._running<1&&this._queue.length>0)return this._running++,({task:o,args:t,resolve:i,reject:r}=this._queue.shift()),e=await async function(){try{return n=await o(...t),function(){return i(n)}}catch(t){return s=t,function(){return r(s)}}}(),this._running--,this._tryToRun(),e()}schedule(t,...e){var s,r,i;return i=r=null,s=new this.Promise((function(t,e){return i=t,r=e})),this._queue.push({task:t,args:e,resolve:i,reject:r}),this._tryToRun(),s}};var U=function(){class t{constructor(e={},...s){var r,i;this._addToQueue=this._addToQueue.bind(this),this._validateOptions(e,s),S.load(e,this.instanceDefaults,this),this._queues=new P(10),this._scheduled={},this._states=new A(["RECEIVED","QUEUED","RUNNING","EXECUTING"].concat(this.trackDoneStatus?["DONE"]:[])),this._limiter=null,this.Events=new C(this),this._submitLock=new L("submit",this.Promise),this._registerLock=new L("register",this.Promise),i=S.load(e,this.storeDefaults,{}),this._store=function(){if("redis"===this.datastore||"ioredis"===this.datastore||null!=this.connection)return r=S.load(e,this.redisStoreDefaults,{}),new T(this,i,r);if("local"===this.datastore)return r=S.load(e,this.localStoreDefaults,{}),new D(this,i,r);throw new t.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`)}.call(this),this._queues.on("leftzero",(()=>{var t;return null!=(t=this._store.heartbeat)&&"function"==typeof t.ref?t.ref():void 0})),this._queues.on("zero",(()=>{var t;return null!=(t=this._store.heartbeat)&&"function"==typeof t.unref?t.unref():void 0}))}_validateOptions(e,s){if(null==e||"object"!=typeof e||0!==s.length)throw new t.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1.")}ready(){return this._store.ready}clients(){return this._store.clients}channel(){return`b_${this.id}`}channel_client(){return`b_${this.id}_${this._store.clientId}`}publish(t){return this._store.__publish__(t)}disconnect(t=!0){return this._store.__disconnect__(t)}chain(t){return this._limiter=t,this}queued(t){return this._queues.queued(t)}clusterQueued(){return this._store.__queued__()}empty(){return 0===this.queued()&&this._submitLock.isEmpty()}running(){return this._store.__running__()}done(){return this._store.__done__()}jobStatus(t){return this._states.jobStatus(t)}jobs(t){return this._states.statusJobs(t)}counts(){return this._states.statusCounts()}_randomIndex(){return Math.random().toString(36).slice(2)}check(t=1){return this._store.__check__(t)}_clearGlobalState(t){return null!=this._scheduled[t]&&(clearTimeout(this._scheduled[t].expiration),delete this._scheduled[t],!0)}async _free(t,e,s,r){var i,n;try{if(({running:n}=await this._store.__free__(t,s.weight)),this.Events.trigger("debug",`Freed ${s.id}`,r),0===n&&this.empty())return this.Events.trigger("idle")}catch(t){return i=t,this.Events.trigger("error",i)}}_run(t,e,s){var r,i,n;return e.doRun(),r=this._clearGlobalState.bind(this,t),n=this._run.bind(this,t,e),i=this._free.bind(this,t,e),this._scheduled[t]={timeout:setTimeout((()=>e.doExecute(this._limiter,r,n,i)),s),expiration:null!=e.options.expiration?setTimeout((function(){return e.doExpire(r,n,i)}),s+e.options.expiration):void 0,job:e}}_drainOne(t){return this._registerLock.schedule((()=>{var e,s,r,i,n;return 0===this.queued()?this.Promise.resolve(null):(n=this._queues.getFirst(),({options:i,args:e}=r=n.first()),null!=t&&i.weight>t?this.Promise.resolve(null):(this.Events.trigger("debug",`Draining ${i.id}`,{args:e,options:i}),s=this._randomIndex(),this._store.__register__(s,i.weight,i.expiration).then((({success:t,wait:o,reservoir:a})=>{var h;return this.Events.trigger("debug",`Drained ${i.id}`,{success:t,args:e,options:i}),t?(n.shift(),(h=this.empty())&&this.Events.trigger("empty"),0===a&&this.Events.trigger("depleted",h),this._run(s,r,o),this.Promise.resolve(i.weight)):this.Promise.resolve(null)}))))}))}_drainAll(t,e=0){return this._drainOne(t).then((s=>{var r;return null!=s?(r=null!=t?t-s:t,this._drainAll(r,e+s)):this.Promise.resolve(e)})).catch((t=>this.Events.trigger("error",t)))}_dropAllQueued(t){return this._queues.shiftAll((function(e){return e.doDrop({message:t})}))}stop(e={}){var s,r;return e=S.load(e,this.stopDefaults),r=t=>{var e;return e=()=>{var e;return(e=this._states.counts)[0]+e[1]+e[2]+e[3]===t},new this.Promise(((t,s)=>e()?t():this.on("done",(()=>{if(e())return this.removeAllListeners("done"),t()}))))},s=e.dropWaitingJobs?(this._run=function(t,s){return s.doDrop({message:e.dropErrorMessage})},this._drainOne=()=>this.Promise.resolve(null),this._registerLock.schedule((()=>this._submitLock.schedule((()=>{var t,s,i;for(t in s=this._scheduled)i=s[t],"RUNNING"===this.jobStatus(i.job.options.id)&&(clearTimeout(i.timeout),clearTimeout(i.expiration),i.job.doDrop({message:e.dropErrorMessage}));return this._dropAllQueued(e.dropErrorMessage),r(0)}))))):this.schedule({priority:9,weight:0},(()=>r(1))),this._receive=function(s){return s._reject(new t.prototype.BottleneckError(e.enqueueErrorMessage))},this.stop=()=>this.Promise.reject(new t.prototype.BottleneckError("stop() has already been called")),s}async _addToQueue(e){var s,r,i,n,o,a,h;({args:s,options:n}=e);try{({reachedHWM:o,blocked:r,strategy:h}=await this._store.__submit__(this.queued(),n.weight))}catch(t){return i=t,this.Events.trigger("debug",`Could not queue ${n.id}`,{args:s,options:n,error:i}),e.doDrop({error:i}),!1}return r?(e.doDrop(),!0):o&&(null!=(a=h===t.prototype.strategy.LEAK?this._queues.shiftLastFrom(n.priority):h===t.prototype.strategy.OVERFLOW_PRIORITY?this._queues.shiftLastFrom(n.priority+1):h===t.prototype.strategy.OVERFLOW?e:void 0)&&a.doDrop(),null==a||h===t.prototype.strategy.OVERFLOW)?(null==a&&e.doDrop(),o):(e.doQueue(o,r),this._queues.push(e),await this._drainAll(),o)}_receive(e){return null!=this._states.jobStatus(e.options.id)?(e._reject(new t.prototype.BottleneckError(`A job with the same id already exists (id=${e.options.id})`)),!1):(e.doReceive(),this._submitLock.schedule(this._addToQueue,e))}submit(...t){var e,s,r,i,n,o,a;return"function"==typeof t[0]?(n=t,[s,...t]=n,[e]=N.call(t,-1),i=S.load({},this.jobDefaults)):(o=t,[i,s,...t]=o,[e]=N.call(t,-1),i=S.load(i,this.jobDefaults)),a=(...t)=>new this.Promise((function(e,r){return s(...t,(function(...t){return(null!=t[0]?r:e)(t)}))})),(r=new I(a,t,i,this.jobDefaults,this.rejectOnDrop,this.Events,this._states,this.Promise)).promise.then((function(t){return"function"==typeof e?e(...t):void 0})).catch((function(t){return Array.isArray(t)?"function"==typeof e?e(...t):void 0:"function"==typeof e?e(t):void 0})),this._receive(r)}schedule(...t){var e,s,r;return"function"==typeof t[0]?([r,...t]=t,s={}):[s,r,...t]=t,e=new I(r,t,s,this.jobDefaults,this.rejectOnDrop,this.Events,this._states,this.Promise),this._receive(e),e.promise}wrap(t){var e,s;return e=this.schedule.bind(this),(s=function(...s){return e(t.bind(this),...s)}).withOptions=function(s,...r){return e(s,t,...r)},s}async updateSettings(t={}){return await this._store.__updateSettings__(S.overwrite(t,this.storeDefaults)),S.overwrite(t,this.instanceDefaults,this),this}currentReservoir(){return this._store.__currentReservoir__()}incrementReservoir(t=0){return this._store.__incrementReservoir__(t)}}return t.default=t,t.Events=C,t.version=t.prototype.version=B.version,t.strategy=t.prototype.strategy={LEAK:1,OVERFLOW:2,OVERFLOW_PRIORITY:4,BLOCK:3},t.BottleneckError=t.prototype.BottleneckError=u,t.Group=t.prototype.Group=R,t.RedisConnection=t.prototype.RedisConnection=O,t.IORedisConnection=t.prototype.IORedisConnection=j,t.Batcher=t.prototype.Batcher=$,t.prototype.jobDefaults={priority:5,weight:1,expiration:null,id:"<no-id>"},t.prototype.storeDefaults={maxConcurrent:null,minTime:0,highWater:null,strategy:t.prototype.strategy.LEAK,penalty:null,reservoir:null,reservoirRefreshInterval:null,reservoirRefreshAmount:null,reservoirIncreaseInterval:null,reservoirIncreaseAmount:null,reservoirIncreaseMaximum:null},t.prototype.localStoreDefaults={Promise,timeout:null,heartbeatInterval:250},t.prototype.redisStoreDefaults={Promise,timeout:null,heartbeatInterval:5e3,clientTimeout:1e4,Redis:null,clientOptions:{},clusterNodes:null,clearDatastore:!1,connection:null},t.prototype.instanceDefaults={datastore:"local",connection:null,id:"<no-id>",rejectOnDrop:!0,trackDoneStatus:!1,Promise},t.prototype.stopDefaults={enqueueErrorMessage:"This limiter has been stopped and cannot accept new jobs.",dropWaitingJobs:!0,dropErrorMessage:"This limiter has been stopped."},t}.call(t);return U}()},310:t=>{"use strict";t.exports=t=>{if("[object Object]"!==Object.prototype.toString.call(t))return!1;const e=Object.getPrototypeOf(t);return null===e||e===Object.prototype}},942:function(t,e,s){"use strict";const r=s(310),{hasOwnProperty:i}=Object.prototype,{propertyIsEnumerable:n}=Object,o=(t,e,s)=>Object.defineProperty(t,e,{value:s,writable:!0,enumerable:!0,configurable:!0}),a=this,h={concatArrays:!1,ignoreUndefined:!1},u=t=>{const e=[];for(const s in t)i.call(t,s)&&e.push(s);if(Object.getOwnPropertySymbols){const s=Object.getOwnPropertySymbols(t);for(const r of s)n.call(t,r)&&e.push(r)}return e};function l(t){return Array.isArray(t)?function(t){const e=t.slice(0,0);return u(t).forEach((s=>{o(e,s,l(t[s]))})),e}(t):r(t)?function(t){const e=null===Object.getPrototypeOf(t)?Object.create(null):{};return u(t).forEach((s=>{o(e,s,l(t[s]))})),e}(t):t}const c=(t,e,s,r)=>(s.forEach((s=>{void 0===e[s]&&r.ignoreUndefined||(s in t&&t[s]!==Object.getPrototypeOf(t)?o(t,s,p(t[s],e[s],r)):o(t,s,l(e[s])))})),t);function p(t,e,s){return s.concatArrays&&Array.isArray(t)&&Array.isArray(e)?((t,e,s)=>{let r=t.slice(0,0),n=0;return[t,e].forEach((e=>{const a=[];for(let s=0;s<e.length;s++)i.call(e,s)&&(a.push(String(s)),o(r,n++,e===t?e[s]:l(e[s])));r=c(r,e,u(e).filter((t=>!a.includes(t))),s)})),r})(t,e,s):r(e)&&r(t)?c(t,e,u(e),s):l(e)}t.exports=function(...t){const e=p(l(h),this!==a&&this||{},h);let s={_:{}};for(const i of t)if(void 0!==i){if(!r(i))throw new TypeError("`"+i+"` is not an Option Object");s=p(s,{_:i},e)}return s._}},322:(t,e,s)=>{const r=s(427),i=s(942),n=s(526),o={jobOptions:{priority:0},rawContent:!1};t.exports=async(t,e)=>{t=r(t,"children"),e=i(o,e);let s=await n(t,e),a=await s.text();if(e.rawContent)return a;let h=a.match(/<url>.*?<\/url>/g).map((t=>{let e=t.match(/<loc>([^<]+)<\/loc>/),s=t.match(/<lastmod>([^<]+)<\/lastmod>/);return{path:r(e[1]),lastmod:s?Date.parse(s[1]):null}}));return h.length&&h[0].path===r(t)&&h.shift(),h}},565:(t,e,s)=>{const r=s(427),i=s(942),n=s(526),o={rawContent:!1};t.exports=async(t,e={})=>{t=r(t,"content"),e=i(o,e);let s=await n(t,e);if(e.rawContent)return await s.text();let a=s.headers.get("Content-Type");if(a.includes("/json"))return s.json();let h=await s.text();return a.includes("text/html")&&(h=h.replace(/\s+/g," ")),h}},526:(t,e,s)=>{const r=s(427).baseURL,i=s(268),n=new(s(209))({reservoir:150,reservoirRefreshAmount:150,reservoirRefreshInterval:5e3,maxConcurrent:10,trackDoneStatus:!0}),o=(t,e)=>i(t,e);t.exports=e=async(t,e)=>{let s=e?.jobOptions||{},i=await n.schedule(s,o,t,e);if(!i.ok)throw new Error(i.statusText);if(!i.url.startsWith(r))throw new Error("Invalid destination URL");return i},e.limiter=n},138:(t,e,s)=>{const r=s(526),i=s(427),n=s(322),o=s(565),a=s(873);t.exports={fetch:r,normalize:i,children:n,content:o,meta:a}},873:(t,e,s)=>{const r=s(427),i=s(942),n=s(526),o={jobOptions:{expiration:3e4},rawContent:!1},a={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"};t.exports=async(t,e)=>{t=r(t,"meta"),e=i(o,e);let s=await n(t,e);if(e.rawContent)return await s.text();if(!s.headers.get("content-type").includes("application/json"))throw new Error("Unexpected response content-type");let h=await s.json();return Object.keys(h).forEach((t=>{"true"===h[t]?h[t]=!0:"false"===h[t]?h[t]=!1:t.endsWith("@TypeHint")?delete h[t]:"string"==typeof h[t]?h[t]=function(t){if(/^\d{4}-\d{2}-\d{2}$/.test(t))return Date.parse(t);let e=/^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(t);return e?Date.parse(e[3]+"-"+a[e[1]]+"-"+e[2]+"T"+e[4]+e[5]):t}(h[t]):Array.isArray(h[t])&&0===h[t].length&&delete h[t]})),Object.keys(h).sort().reduce(((t,e)=>(t[e]=h[e],t)),{})}},427:(t,e)=>{const s="https://www.canada.ca/";t.exports=e=(t,e="path")=>{if("string"==typeof t)t=new URL(t,s);else if(!(t instanceof URL))throw new TypeError("string or URL object expected");if(t.protocol="https",!t.href.startsWith(s))throw new Error("URL must start with "+s);let r=t.pathname.startsWith("/content/dam");if(r||(t.pathname=t.pathname.replace(/^\/content\/canadasite\//,"")),!/^\/(en|fr|content\/dam)(\/|\.|$)/.test(t.pathname))throw new Error("Invalid root");return t.pathname=t.pathname.replace(/\/+$/,""),"path"!==e&&t.searchParams.set("_",Date.now()),t.pathname.includes("/_jcr_content/par")?function(t,e){if("path"===e)throw new Error("Cant determine path of a reference node directly");if("meta"===e)t.pathname=t.pathname.replace(/\/image\.img\.\w+\//,"/image.json/");else if("children"===e)throw new Error("Cant load children of a reference node");return t.href}(t,e):r?function(t,e){let s=/(\/|\/\w+)$/.test(t.pathname);if("meta"===e)t.pathname+=s?".json":"/_jcr_content.json";else{if("children"===e)throw new Error("Cant load children of an asset node");if("content"===e&&s)throw new Error("Cant load content of an asset node")}return"path"===e?t.pathname:t.href}(t,e):function(t,e){return t.pathname=t.pathname.replace(/\/?\.(sitemap\.xml|[^/.]+)$/,""),"meta"===e?t.pathname+="/_jcr_content.json":"children"===e?t.pathname+=".sitemap.xml":"content"===e&&(t.pathname+=".html"),"path"===e?t.pathname:t.href}(t,e)},e.baseURL=s},268:e=>{"use strict";e.exports=t}},s={};function r(t){var i=s[t];if(void 0!==i)return i.exports;var n=s[t]={exports:{}};return e[t].call(n.exports,n,n.exports,r),n.exports}return r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),r(138)})()));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("cross-fetch")):"function"==typeof define&&define.amd?define("ca",["cross-fetch"],e):"object"==typeof exports?exports.ca=e(require("cross-fetch")):t.ca=e(t.fetch)}("undefined"!=typeof self?self:this,(t=>(()=>{var e={209:function(t,e,s){t.exports=function(){"use strict";var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==s.g?s.g:"undefined"!=typeof self?self:{};var e,r,i={load:function(t,e,s={}){var r,i,n;for(r in e)n=e[r],s[r]=null!=(i=t[r])?i:n;return s},overwrite:function(t,e,s={}){var r,i;for(r in t)i=t[r],void 0!==e[r]&&(s[r]=i);return s}},n=class{constructor(t,e){this.incr=t,this.decr=e,this._first=null,this._last=null,this.length=0}push(t){var e;this.length++,"function"==typeof this.incr&&this.incr(),e={value:t,prev:this._last,next:null},null!=this._last?(this._last.next=e,this._last=e):this._first=this._last=e}shift(){var t;if(null!=this._first)return this.length--,"function"==typeof this.decr&&this.decr(),t=this._first.value,null!=(this._first=this._first.next)?this._first.prev=null:this._last=null,t}first(){if(null!=this._first)return this._first.value}getArray(){var t,e,s;for(t=this._first,s=[];null!=t;)s.push((e=t,t=t.next,e.value));return s}forEachShift(t){var e;for(e=this.shift();null!=e;)t(e),e=this.shift()}debug(){var t,e,s,r,i;for(t=this._first,i=[];null!=t;)i.push((e=t,t=t.next,{value:e.value,prev:null!=(s=e.prev)?s.value:void 0,next:null!=(r=e.next)?r.value:void 0}));return i}},o=class{constructor(t){if(this.instance=t,this._events={},null!=this.instance.on||null!=this.instance.once||null!=this.instance.removeAllListeners)throw new Error("An Emitter already exists for this object");this.instance.on=(t,e)=>this._addListener(t,"many",e),this.instance.once=(t,e)=>this._addListener(t,"once",e),this.instance.removeAllListeners=(t=null)=>null!=t?delete this._events[t]:this._events={}}_addListener(t,e,s){var r;return null==(r=this._events)[t]&&(r[t]=[]),this._events[t].push({cb:s,status:e}),this.instance}listenerCount(t){return null!=this._events[t]?this._events[t].length:0}async trigger(t,...e){var s,r;try{if("debug"!==t&&this.trigger("debug",`Event triggered: ${t}`,e),null==this._events[t])return;return this._events[t]=this._events[t].filter((function(t){return"none"!==t.status})),r=this._events[t].map((async t=>{var s,r;if("none"!==t.status){"once"===t.status&&(t.status="none");try{return"function"==typeof(null!=(r="function"==typeof t.cb?t.cb(...e):void 0)?r.then:void 0)?await r:r}catch(t){return s=t,this.trigger("error",s),null}}})),(await Promise.all(r)).find((function(t){return null!=t}))}catch(t){return s=t,this.trigger("error",s),null}}};e=n,r=o;var a,h,u=class extends Error{};h=i,a=u;var l,c,d=class{constructor(t,e,s,r,i,n,o,a){this.task=t,this.args=e,this.rejectOnDrop=i,this.Events=n,this._states=o,this.Promise=a,this.options=h.load(s,r),this.options.priority=this._sanitizePriority(this.options.priority),this.options.id===r.id&&(this.options.id=`${this.options.id}-${this._randomIndex()}`),this.promise=new this.Promise(((t,e)=>{this._resolve=t,this._reject=e})),this.retryCount=0}_sanitizePriority(t){var e;return(e=~~t!==t?5:t)<0?0:e>9?9:e}_randomIndex(){return Math.random().toString(36).slice(2)}doDrop({error:t,message:e="This job has been dropped by Bottleneck"}={}){return!!this._states.remove(this.options.id)&&(this.rejectOnDrop&&this._reject(null!=t?t:new a(e)),this.Events.trigger("dropped",{args:this.args,options:this.options,task:this.task,promise:this.promise}),!0)}_assertStatus(t){var e;if((e=this._states.jobStatus(this.options.id))!==t&&("DONE"!==t||null!==e))throw new a(`Invalid job status ${e}, expected ${t}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`)}doReceive(){return this._states.start(this.options.id),this.Events.trigger("received",{args:this.args,options:this.options})}doQueue(t,e){return this._assertStatus("RECEIVED"),this._states.next(this.options.id),this.Events.trigger("queued",{args:this.args,options:this.options,reachedHWM:t,blocked:e})}doRun(){return 0===this.retryCount?(this._assertStatus("QUEUED"),this._states.next(this.options.id)):this._assertStatus("EXECUTING"),this.Events.trigger("scheduled",{args:this.args,options:this.options})}async doExecute(t,e,s,r){var i,n,o;0===this.retryCount?(this._assertStatus("RUNNING"),this._states.next(this.options.id)):this._assertStatus("EXECUTING"),n={args:this.args,options:this.options,retryCount:this.retryCount},this.Events.trigger("executing",n);try{if(o=await(null!=t?t.schedule(this.options,this.task,...this.args):this.task(...this.args)),e())return this.doDone(n),await r(this.options,n),this._assertStatus("DONE"),this._resolve(o)}catch(t){return i=t,this._onFailure(i,n,e,s,r)}}doExpire(t,e,s){var r,i;return this._states.jobStatus("RUNNING"===this.options.id)&&this._states.next(this.options.id),this._assertStatus("EXECUTING"),i={args:this.args,options:this.options,retryCount:this.retryCount},r=new a(`This job timed out after ${this.options.expiration} ms.`),this._onFailure(r,i,t,e,s)}async _onFailure(t,e,s,r,i){var n,o;if(s())return null!=(n=await this.Events.trigger("failed",t,e))?(o=~~n,this.Events.trigger("retry",`Retrying ${this.options.id} after ${o} ms`,e),this.retryCount++,r(o)):(this.doDone(e),await i(this.options,e),this._assertStatus("DONE"),this._reject(t))}doDone(t){return this._assertStatus("EXECUTING"),this._states.next(this.options.id),this.Events.trigger("done",t)}};c=i,l=u;var p;p=u;var _;_=n;var f,v,m,g,y,w="2.19.5",b={version:w},E=Object.freeze({version:w,default:b}),O=()=>console.log("You must import the full version of Bottleneck in order to use this feature."),x=()=>console.log("You must import the full version of Bottleneck in order to use this feature.");y=i,f=o,m=O,v=x,g=()=>console.log("You must import the full version of Bottleneck in order to use this feature.");var j,R,k=function(){class t{constructor(t={}){this.deleteKey=this.deleteKey.bind(this),this.limiterOptions=t,y.load(this.limiterOptions,this.defaults,this),this.Events=new f(this),this.instances={},this.Bottleneck=U,this._startAutoCleanup(),this.sharedConnection=null!=this.connection,null==this.connection&&("redis"===this.limiterOptions.datastore?this.connection=new m(Object.assign({},this.limiterOptions,{Events:this.Events})):"ioredis"===this.limiterOptions.datastore&&(this.connection=new v(Object.assign({},this.limiterOptions,{Events:this.Events}))))}key(t=""){var e;return null!=(e=this.instances[t])?e:(()=>{var e;return e=this.instances[t]=new this.Bottleneck(Object.assign(this.limiterOptions,{id:`${this.id}-${t}`,timeout:this.timeout,connection:this.connection})),this.Events.trigger("created",e,t),e})()}async deleteKey(t=""){var e,s;return s=this.instances[t],this.connection&&(e=await this.connection.__runCommand__(["del",...g.allKeys(`${this.id}-${t}`)])),null!=s&&(delete this.instances[t],await s.disconnect()),null!=s||e>0}limiters(){var t,e,s,r;for(t in s=[],e=this.instances)r=e[t],s.push({key:t,limiter:r});return s}keys(){return Object.keys(this.instances)}async clusterKeys(){var t,e,s,r,i,n,o,a,h;if(null==this.connection)return this.Promise.resolve(this.keys());for(n=[],t=null,h=`b_${this.id}-`.length,e="_settings".length;0!==t;)for([a,s]=await this.connection.__runCommand__(["scan",null!=t?t:0,"match",`b_${this.id}-*_settings`,"count",1e4]),t=~~a,r=0,o=s.length;r<o;r++)i=s[r],n.push(i.slice(h,-e));return n}_startAutoCleanup(){var t;return clearInterval(this.interval),"function"==typeof(t=this.interval=setInterval((async()=>{var t,e,s,r,i,n;for(e in i=Date.now(),r=[],s=this.instances){n=s[e];try{await n._store.__groupCheck__(i)?r.push(this.deleteKey(e)):r.push(void 0)}catch(e){t=e,r.push(n.Events.trigger("error",t))}}return r}),this.timeout/2)).unref?t.unref():void 0}updateSettings(t={}){if(y.overwrite(t,this.defaults,this),y.overwrite(t,t,this.limiterOptions),null!=t.timeout)return this._startAutoCleanup()}disconnect(t=!0){var e;if(!this.sharedConnection)return null!=(e=this.connection)?e.disconnect(t):void 0}}return t.prototype.defaults={timeout:3e5,connection:null,Promise,id:"group-key"},t}.call(t);R=i,j=o;var I,D,C,L,T,S,P,A,q,$=function(){class t{constructor(t={}){this.options=t,R.load(this.options,this.defaults,this),this.Events=new j(this),this._arr=[],this._resetPromise(),this._lastFlush=Date.now()}_resetPromise(){return this._promise=new this.Promise(((t,e)=>this._resolve=t))}_flush(){return clearTimeout(this._timeout),this._lastFlush=Date.now(),this._resolve(),this.Events.trigger("batch",this._arr),this._arr=[],this._resetPromise()}add(t){var e;return this._arr.push(t),e=this._promise,this._arr.length===this.maxSize?this._flush():null!=this.maxTime&&1===this._arr.length&&(this._timeout=setTimeout((()=>this._flush()),this.maxTime)),e}}return t.prototype.defaults={maxTime:null,maxSize:null,Promise},t}.call(t),B=(q=E)&&q.default||q,N=[].splice;A=i,L=class{constructor(t){this.Events=new r(this),this._length=0,this._lists=function(){var s,r,i;for(i=[],s=1,r=t;1<=r?s<=r:s>=r;1<=r?++s:--s)i.push(new e((()=>this.incr()),(()=>this.decr())));return i}.call(this)}incr(){if(0==this._length++)return this.Events.trigger("leftzero")}decr(){if(0==--this._length)return this.Events.trigger("zero")}push(t){return this._lists[t.options.priority].push(t)}queued(t){return null!=t?this._lists[t].length:this._length}shiftAll(t){return this._lists.forEach((function(e){return e.forEachShift(t)}))}getFirst(t=this._lists){var e,s,r;for(e=0,s=t.length;e<s;e++)if((r=t[e]).length>0)return r;return[]}shiftLastFrom(t){return this.getFirst(this._lists.slice(t).reverse()).shift()}},D=d,C=class{constructor(t,e,s){this.instance=t,this.storeOptions=e,this.clientId=this.instance._randomIndex(),c.load(s,s,this),this._nextRequest=this._lastReservoirRefresh=this._lastReservoirIncrease=Date.now(),this._running=0,this._done=0,this._unblockTime=0,this.ready=this.Promise.resolve(),this.clients={},this._startHeartbeat()}_startHeartbeat(){var t;return null==this.heartbeat&&(null!=this.storeOptions.reservoirRefreshInterval&&null!=this.storeOptions.reservoirRefreshAmount||null!=this.storeOptions.reservoirIncreaseInterval&&null!=this.storeOptions.reservoirIncreaseAmount)?"function"==typeof(t=this.heartbeat=setInterval((()=>{var t,e,s,r,i;if(r=Date.now(),null!=this.storeOptions.reservoirRefreshInterval&&r>=this._lastReservoirRefresh+this.storeOptions.reservoirRefreshInterval&&(this._lastReservoirRefresh=r,this.storeOptions.reservoir=this.storeOptions.reservoirRefreshAmount,this.instance._drainAll(this.computeCapacity())),null!=this.storeOptions.reservoirIncreaseInterval&&r>=this._lastReservoirIncrease+this.storeOptions.reservoirIncreaseInterval&&(({reservoirIncreaseAmount:t,reservoirIncreaseMaximum:s,reservoir:i}=this.storeOptions),this._lastReservoirIncrease=r,(e=null!=s?Math.min(t,s-i):t)>0))return this.storeOptions.reservoir+=e,this.instance._drainAll(this.computeCapacity())}),this.heartbeatInterval)).unref?t.unref():void 0:clearInterval(this.heartbeat)}async __publish__(t){return await this.yieldLoop(),this.instance.Events.trigger("message",t.toString())}async __disconnect__(t){return await this.yieldLoop(),clearInterval(this.heartbeat),this.Promise.resolve()}yieldLoop(t=0){return new this.Promise((function(e,s){return setTimeout(e,t)}))}computePenalty(){var t;return null!=(t=this.storeOptions.penalty)?t:15*this.storeOptions.minTime||5e3}async __updateSettings__(t){return await this.yieldLoop(),c.overwrite(t,t,this.storeOptions),this._startHeartbeat(),this.instance._drainAll(this.computeCapacity()),!0}async __running__(){return await this.yieldLoop(),this._running}async __queued__(){return await this.yieldLoop(),this.instance.queued()}async __done__(){return await this.yieldLoop(),this._done}async __groupCheck__(t){return await this.yieldLoop(),this._nextRequest+this.timeout<t}computeCapacity(){var t,e;return({maxConcurrent:t,reservoir:e}=this.storeOptions),null!=t&&null!=e?Math.min(t-this._running,e):null!=t?t-this._running:null!=e?e:null}conditionsCheck(t){var e;return null==(e=this.computeCapacity())||t<=e}async __incrementReservoir__(t){var e;return await this.yieldLoop(),e=this.storeOptions.reservoir+=t,this.instance._drainAll(this.computeCapacity()),e}async __currentReservoir__(){return await this.yieldLoop(),this.storeOptions.reservoir}isBlocked(t){return this._unblockTime>=t}check(t,e){return this.conditionsCheck(t)&&this._nextRequest-e<=0}async __check__(t){var e;return await this.yieldLoop(),e=Date.now(),this.check(t,e)}async __register__(t,e,s){var r,i;return await this.yieldLoop(),r=Date.now(),this.conditionsCheck(e)?(this._running+=e,null!=this.storeOptions.reservoir&&(this.storeOptions.reservoir-=e),i=Math.max(this._nextRequest-r,0),this._nextRequest=r+i+this.storeOptions.minTime,{success:!0,wait:i,reservoir:this.storeOptions.reservoir}):{success:!1}}strategyIsBlock(){return 3===this.storeOptions.strategy}async __submit__(t,e){var s,r,i;if(await this.yieldLoop(),null!=this.storeOptions.maxConcurrent&&e>this.storeOptions.maxConcurrent)throw new l(`Impossible to add a job having a weight of ${e} to a limiter having a maxConcurrent setting of ${this.storeOptions.maxConcurrent}`);return r=Date.now(),i=null!=this.storeOptions.highWater&&t===this.storeOptions.highWater&&!this.check(e,r),(s=this.strategyIsBlock()&&(i||this.isBlocked(r)))&&(this._unblockTime=r+this.computePenalty(),this._nextRequest=this._unblockTime+this.storeOptions.minTime,this.instance._dropAllQueued()),{reachedHWM:i,blocked:s,strategy:this.storeOptions.strategy}}async __free__(t,e){return await this.yieldLoop(),this._running-=e,this._done+=e,this.instance._drainAll(this.computeCapacity()),{running:this._running}}},T=()=>console.log("You must import the full version of Bottleneck in order to use this feature."),I=o,S=class{constructor(t){this.status=t,this._jobs={},this.counts=this.status.map((function(){return 0}))}next(t){var e,s;return s=(e=this._jobs[t])+1,null!=e&&s<this.status.length?(this.counts[e]--,this.counts[s]++,this._jobs[t]++):null!=e?(this.counts[e]--,delete this._jobs[t]):void 0}start(t){return 0,this._jobs[t]=0,this.counts[0]++}remove(t){var e;return null!=(e=this._jobs[t])&&(this.counts[e]--,delete this._jobs[t]),null!=e}jobStatus(t){var e;return null!=(e=this.status[this._jobs[t]])?e:null}statusJobs(t){var e,s,r,i;if(null!=t){if((s=this.status.indexOf(t))<0)throw new p(`status must be one of ${this.status.join(", ")}`);for(e in i=[],r=this._jobs)r[e]===s&&i.push(e);return i}return Object.keys(this._jobs)}statusCounts(){return this.counts.reduce(((t,e,s)=>(t[this.status[s]]=e,t)),{})}},P=class{constructor(t,e){this.schedule=this.schedule.bind(this),this.name=t,this.Promise=e,this._running=0,this._queue=new _}isEmpty(){return 0===this._queue.length}async _tryToRun(){var t,e,s,r,i,n,o;if(this._running<1&&this._queue.length>0)return this._running++,({task:o,args:t,resolve:i,reject:r}=this._queue.shift()),e=await async function(){try{return n=await o(...t),function(){return i(n)}}catch(t){return s=t,function(){return r(s)}}}(),this._running--,this._tryToRun(),e()}schedule(t,...e){var s,r,i;return i=r=null,s=new this.Promise((function(t,e){return i=t,r=e})),this._queue.push({task:t,args:e,resolve:i,reject:r}),this._tryToRun(),s}};var U=function(){class t{constructor(e={},...s){var r,i;this._addToQueue=this._addToQueue.bind(this),this._validateOptions(e,s),A.load(e,this.instanceDefaults,this),this._queues=new L(10),this._scheduled={},this._states=new S(["RECEIVED","QUEUED","RUNNING","EXECUTING"].concat(this.trackDoneStatus?["DONE"]:[])),this._limiter=null,this.Events=new I(this),this._submitLock=new P("submit",this.Promise),this._registerLock=new P("register",this.Promise),i=A.load(e,this.storeDefaults,{}),this._store=function(){if("redis"===this.datastore||"ioredis"===this.datastore||null!=this.connection)return r=A.load(e,this.redisStoreDefaults,{}),new T(this,i,r);if("local"===this.datastore)return r=A.load(e,this.localStoreDefaults,{}),new C(this,i,r);throw new t.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`)}.call(this),this._queues.on("leftzero",(()=>{var t;return null!=(t=this._store.heartbeat)&&"function"==typeof t.ref?t.ref():void 0})),this._queues.on("zero",(()=>{var t;return null!=(t=this._store.heartbeat)&&"function"==typeof t.unref?t.unref():void 0}))}_validateOptions(e,s){if(null==e||"object"!=typeof e||0!==s.length)throw new t.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1.")}ready(){return this._store.ready}clients(){return this._store.clients}channel(){return`b_${this.id}`}channel_client(){return`b_${this.id}_${this._store.clientId}`}publish(t){return this._store.__publish__(t)}disconnect(t=!0){return this._store.__disconnect__(t)}chain(t){return this._limiter=t,this}queued(t){return this._queues.queued(t)}clusterQueued(){return this._store.__queued__()}empty(){return 0===this.queued()&&this._submitLock.isEmpty()}running(){return this._store.__running__()}done(){return this._store.__done__()}jobStatus(t){return this._states.jobStatus(t)}jobs(t){return this._states.statusJobs(t)}counts(){return this._states.statusCounts()}_randomIndex(){return Math.random().toString(36).slice(2)}check(t=1){return this._store.__check__(t)}_clearGlobalState(t){return null!=this._scheduled[t]&&(clearTimeout(this._scheduled[t].expiration),delete this._scheduled[t],!0)}async _free(t,e,s,r){var i,n;try{if(({running:n}=await this._store.__free__(t,s.weight)),this.Events.trigger("debug",`Freed ${s.id}`,r),0===n&&this.empty())return this.Events.trigger("idle")}catch(t){return i=t,this.Events.trigger("error",i)}}_run(t,e,s){var r,i,n;return e.doRun(),r=this._clearGlobalState.bind(this,t),n=this._run.bind(this,t,e),i=this._free.bind(this,t,e),this._scheduled[t]={timeout:setTimeout((()=>e.doExecute(this._limiter,r,n,i)),s),expiration:null!=e.options.expiration?setTimeout((function(){return e.doExpire(r,n,i)}),s+e.options.expiration):void 0,job:e}}_drainOne(t){return this._registerLock.schedule((()=>{var e,s,r,i,n;return 0===this.queued()?this.Promise.resolve(null):(n=this._queues.getFirst(),({options:i,args:e}=r=n.first()),null!=t&&i.weight>t?this.Promise.resolve(null):(this.Events.trigger("debug",`Draining ${i.id}`,{args:e,options:i}),s=this._randomIndex(),this._store.__register__(s,i.weight,i.expiration).then((({success:t,wait:o,reservoir:a})=>{var h;return this.Events.trigger("debug",`Drained ${i.id}`,{success:t,args:e,options:i}),t?(n.shift(),(h=this.empty())&&this.Events.trigger("empty"),0===a&&this.Events.trigger("depleted",h),this._run(s,r,o),this.Promise.resolve(i.weight)):this.Promise.resolve(null)}))))}))}_drainAll(t,e=0){return this._drainOne(t).then((s=>{var r;return null!=s?(r=null!=t?t-s:t,this._drainAll(r,e+s)):this.Promise.resolve(e)})).catch((t=>this.Events.trigger("error",t)))}_dropAllQueued(t){return this._queues.shiftAll((function(e){return e.doDrop({message:t})}))}stop(e={}){var s,r;return e=A.load(e,this.stopDefaults),r=t=>{var e;return e=()=>{var e;return(e=this._states.counts)[0]+e[1]+e[2]+e[3]===t},new this.Promise(((t,s)=>e()?t():this.on("done",(()=>{if(e())return this.removeAllListeners("done"),t()}))))},s=e.dropWaitingJobs?(this._run=function(t,s){return s.doDrop({message:e.dropErrorMessage})},this._drainOne=()=>this.Promise.resolve(null),this._registerLock.schedule((()=>this._submitLock.schedule((()=>{var t,s,i;for(t in s=this._scheduled)i=s[t],"RUNNING"===this.jobStatus(i.job.options.id)&&(clearTimeout(i.timeout),clearTimeout(i.expiration),i.job.doDrop({message:e.dropErrorMessage}));return this._dropAllQueued(e.dropErrorMessage),r(0)}))))):this.schedule({priority:9,weight:0},(()=>r(1))),this._receive=function(s){return s._reject(new t.prototype.BottleneckError(e.enqueueErrorMessage))},this.stop=()=>this.Promise.reject(new t.prototype.BottleneckError("stop() has already been called")),s}async _addToQueue(e){var s,r,i,n,o,a,h;({args:s,options:n}=e);try{({reachedHWM:o,blocked:r,strategy:h}=await this._store.__submit__(this.queued(),n.weight))}catch(t){return i=t,this.Events.trigger("debug",`Could not queue ${n.id}`,{args:s,options:n,error:i}),e.doDrop({error:i}),!1}return r?(e.doDrop(),!0):o&&(null!=(a=h===t.prototype.strategy.LEAK?this._queues.shiftLastFrom(n.priority):h===t.prototype.strategy.OVERFLOW_PRIORITY?this._queues.shiftLastFrom(n.priority+1):h===t.prototype.strategy.OVERFLOW?e:void 0)&&a.doDrop(),null==a||h===t.prototype.strategy.OVERFLOW)?(null==a&&e.doDrop(),o):(e.doQueue(o,r),this._queues.push(e),await this._drainAll(),o)}_receive(e){return null!=this._states.jobStatus(e.options.id)?(e._reject(new t.prototype.BottleneckError(`A job with the same id already exists (id=${e.options.id})`)),!1):(e.doReceive(),this._submitLock.schedule(this._addToQueue,e))}submit(...t){var e,s,r,i,n,o,a;return"function"==typeof t[0]?(n=t,[s,...t]=n,[e]=N.call(t,-1),i=A.load({},this.jobDefaults)):(o=t,[i,s,...t]=o,[e]=N.call(t,-1),i=A.load(i,this.jobDefaults)),a=(...t)=>new this.Promise((function(e,r){return s(...t,(function(...t){return(null!=t[0]?r:e)(t)}))})),(r=new D(a,t,i,this.jobDefaults,this.rejectOnDrop,this.Events,this._states,this.Promise)).promise.then((function(t){return"function"==typeof e?e(...t):void 0})).catch((function(t){return Array.isArray(t)?"function"==typeof e?e(...t):void 0:"function"==typeof e?e(t):void 0})),this._receive(r)}schedule(...t){var e,s,r;return"function"==typeof t[0]?([r,...t]=t,s={}):[s,r,...t]=t,e=new D(r,t,s,this.jobDefaults,this.rejectOnDrop,this.Events,this._states,this.Promise),this._receive(e),e.promise}wrap(t){var e,s;return e=this.schedule.bind(this),(s=function(...s){return e(t.bind(this),...s)}).withOptions=function(s,...r){return e(s,t,...r)},s}async updateSettings(t={}){return await this._store.__updateSettings__(A.overwrite(t,this.storeDefaults)),A.overwrite(t,this.instanceDefaults,this),this}currentReservoir(){return this._store.__currentReservoir__()}incrementReservoir(t=0){return this._store.__incrementReservoir__(t)}}return t.default=t,t.Events=I,t.version=t.prototype.version=B.version,t.strategy=t.prototype.strategy={LEAK:1,OVERFLOW:2,OVERFLOW_PRIORITY:4,BLOCK:3},t.BottleneckError=t.prototype.BottleneckError=u,t.Group=t.prototype.Group=k,t.RedisConnection=t.prototype.RedisConnection=O,t.IORedisConnection=t.prototype.IORedisConnection=x,t.Batcher=t.prototype.Batcher=$,t.prototype.jobDefaults={priority:5,weight:1,expiration:null,id:"<no-id>"},t.prototype.storeDefaults={maxConcurrent:null,minTime:0,highWater:null,strategy:t.prototype.strategy.LEAK,penalty:null,reservoir:null,reservoirRefreshInterval:null,reservoirRefreshAmount:null,reservoirIncreaseInterval:null,reservoirIncreaseAmount:null,reservoirIncreaseMaximum:null},t.prototype.localStoreDefaults={Promise,timeout:null,heartbeatInterval:250},t.prototype.redisStoreDefaults={Promise,timeout:null,heartbeatInterval:5e3,clientTimeout:1e4,Redis:null,clientOptions:{},clusterNodes:null,clearDatastore:!1,connection:null},t.prototype.instanceDefaults={datastore:"local",connection:null,id:"<no-id>",rejectOnDrop:!0,trackDoneStatus:!1,Promise},t.prototype.stopDefaults={enqueueErrorMessage:"This limiter has been stopped and cannot accept new jobs.",dropWaitingJobs:!0,dropErrorMessage:"This limiter has been stopped."},t}.call(t);return U}()},920:(t,e,s)=>{const r=s(797),i=s(36);t.exports=async t=>{t=r(t,"children");let e=await i(t),s=e.data.match(/<url>.*?<\/url>/g).map((t=>{let e=t.match(/<loc>([^<]+)<\/loc>/),s=t.match(/<lastmod>([^<]+)<\/lastmod>/);return{url:r(e[1]).pathname,lastmod:s?new Date(s[1]).toISOString():null}}));return s.length&&s[0].url===r(t).pathname&&s.shift(),e.data=s,e}},420:(t,e,s)=>{const r=s(797),i=s(36);t.exports=async t=>(t=r(t,"content"),i(t))},30:(t,e,s)=>{const r=s(797),i=s(36),n={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"};function o(t){if(/^\d{4}-\d{2}-\d{2}$/.test(t))return new Date(t).toISOString();let e=/^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(t);return e?new Date(e[3]+"-"+n[e[1]]+"-"+e[2]+"T"+e[4]+e[5]).toISOString():t}t.exports=async t=>{t=r(t,"meta");let e=await i(t),s=e.data;for(const[t,e]of Object.entries(s))"true"===e?s[t]=!0:"false"===e?s[t]=!1:t.endsWith("@TypeHint")?delete s[t]:"string"==typeof e?s[t]=o(s[t].trim()):Array.isArray(e)&&0===e.length&&delete s[t];return e.data=Object.keys(e.data).sort().reduce(((t,e)=>(t[e]=s[e],t)),{}),e}},797:(t,e)=>{const s="https://www.canada.ca/";t.exports=e=(t,e="path")=>{if("string"==typeof t)t=new URL(t,s);else if(!(t instanceof URL))throw new TypeError("string or URL object expected");if(t.protocol="https",!t.href.startsWith(s))throw new Error("URL must start with "+s);let r=t.pathname.startsWith("/content/dam");if(r||(t.pathname=t.pathname.replace(/^\/content\/canadasite\//,"")),!/^\/(en|fr|content\/dam)(\/|\.|$)/.test(t.pathname))throw new Error("Invalid root");return t.pathname=t.pathname.replace(/\/+$/,""),t.pathname.includes("/_jcr_content/par")?function(t,e){if("path"===e)throw new Error("Cant determine path of a reference node directly");if("meta"===e)t.pathname=t.pathname.replace(/\/image\.img\.\w+\//,"/image.json/");else if("children"===e)throw new Error("Cant load children of a reference node");return t}(t,e):r?function(t,e){let s=/(\/|\/\w+)$/.test(t.pathname);if("meta"===e)t.pathname+=s?".json":"/_jcr_content.json";else{if("children"===e)throw new Error("Cant load children of an asset node");if("content"===e&&s)throw new Error("Cant load content of an asset node")}return t}(t,e):function(t,e){return t.pathname=t.pathname.replace(/\/?\.(sitemap\.xml|[^/.]+)$/,""),"meta"===e?t.pathname+="/_jcr_content.json":"children"===e?t.pathname+=".sitemap.xml":"content"===e&&(t.pathname+=".html"),t}(t,e)},e.baseURL=s},36:(t,e,s)=>{const r=s(797),i=s(268),n=new(s(209))({reservoir:150,reservoirRefreshAmount:150,reservoirRefreshInterval:5e3,maxConcurrent:10,trackDoneStatus:!0}),o=t=>i(t);async function a(t){return t.headers.get("content-type").includes("application/json")?t.json():t.text()}t.exports=e=async function(t){"string"==typeof t&&(t=new URL(t,r.baseURL)),t.searchParams.set("_",Date.now());let e=await n.schedule(o,t);if(!e.ok)throw new Error(e.statusText);if(!e.url.startsWith(r.baseURL))throw new Error("Invalid destination URL");let s=r(t).pathname!==r(e.url).pathname;return{url:e.url,redirected:s,data:await a(e)}},e.limiter=n},138:(t,e,s)=>{const r=s(36),i=s(797),n=s(920),o=s(420),a=s(30);t.exports={request:r,normalize:i,children:n,content:o,meta:a}},268:e=>{"use strict";e.exports=t}},s={};function r(t){var i=s[t];if(void 0!==i)return i.exports;var n=s[t]={exports:{}};return e[t].call(n.exports,n,n.exports,r),n.exports}return r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),r(138)})()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canada-api",
3
- "version": "2.0.4",
3
+ "version": "3.0.0",
4
4
  "description": "Cross platform API to fetch data from canada.ca",
5
5
  "browser": "dist/ca.js",
6
6
  "main": "src/index.js",
@@ -0,0 +1,35 @@
1
+ const normalize = require('../core/normalize.js')
2
+ const request = require('../core/request.js')
3
+
4
+ /**
5
+ * Get list of child nodes from sitemap
6
+ * @param {string} url node url
7
+ * @returns {Promise<Array>}
8
+ */
9
+ const children = async url => {
10
+ url = normalize(url, 'children')
11
+
12
+ let response = await request(url)
13
+
14
+ // Parse XML sitemap
15
+ let children = response.data.match(/<url>.*?<\/url>/g).map(url => {
16
+ let loc = url.match(/<loc>([^<]+)<\/loc>/)
17
+ let mod = url.match(/<lastmod>([^<]+)<\/lastmod>/)
18
+
19
+ return {
20
+ url: normalize(loc[1]).pathname,
21
+ lastmod: mod ? new Date(mod[1]).toISOString() : null
22
+ }
23
+ })
24
+
25
+ // First entry may be the parent
26
+ if (children.length && children[0].url === normalize(url).pathname) {
27
+ children.shift()
28
+ }
29
+
30
+ response.data = children
31
+ return response
32
+ }
33
+
34
+ // Default export
35
+ module.exports = exports = children
@@ -0,0 +1,15 @@
1
+ const normalize = require('../core/normalize.js')
2
+ const request = require('../core/request.js')
3
+
4
+ /**
5
+ * Get node content
6
+ * @param {string} url node URL
7
+ * @returns {Promise<any>}
8
+ */
9
+ const content = async url => {
10
+ url = normalize(url, 'content')
11
+ return request(url)
12
+ }
13
+
14
+ // Default export
15
+ module.exports = exports = content
@@ -0,0 +1,71 @@
1
+ const normalize = require('../core/normalize.js')
2
+ const request = require('../core/request.js')
3
+
4
+ /**
5
+ * Get node metadata from jcr content
6
+ * @param {string} url node path
7
+ * @returns {Promise<Object>}
8
+ */
9
+ const meta = async url => {
10
+ url = normalize(url, 'meta')
11
+
12
+ let response = await request(url)
13
+ let json = response.data
14
+
15
+ // Format some properties for consistency
16
+ for (const [key, value] of Object.entries(json)) {
17
+ if (value === 'true') {
18
+ json[key] = true
19
+ } else if (value === 'false') {
20
+ json[key] = false
21
+ } else if (key.endsWith('@TypeHint')) {
22
+ delete json[key]
23
+ } else if (typeof value === 'string') {
24
+ json[key] = maybeParseDate(json[key].trim())
25
+ } else if (Array.isArray(value) && value.length === 0) {
26
+ delete json[key]
27
+ }
28
+ }
29
+
30
+ // Sort object keys alphabetically for readability
31
+ response.data = Object.keys(response.data).sort().reduce((obj, key) => {
32
+ obj[key] = json[key]
33
+ return obj
34
+ }, {})
35
+
36
+ return response
37
+ }
38
+
39
+ /**
40
+ * Map month name to number
41
+ * @const {object}
42
+ * @private
43
+ */
44
+ const months = {
45
+ 'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
46
+ 'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'
47
+ }
48
+
49
+ /**
50
+ * Try to parse a date
51
+ * @param {string} date
52
+ * @returns {number|string}
53
+ * @private
54
+ */
55
+ function maybeParseDate(date) {
56
+ // Simple
57
+ if (/^\d{4}-\d{2}-\d{2}$/.test(date)) {
58
+ return new Date(date).toISOString()
59
+ }
60
+
61
+ // RFC1123
62
+ let m = /^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(date)
63
+ if (m) {
64
+ return new Date(m[3] + '-' + months[m[1]] + '-' + m[2] + 'T' + m[4] + m[5]).toISOString()
65
+ }
66
+
67
+ return date
68
+ }
69
+
70
+ // Default export
71
+ module.exports = exports = meta
@@ -43,11 +43,6 @@ const normalize = (url, type = 'path') => {
43
43
  // Strip Trailing slashes
44
44
  url.pathname = url.pathname.replace(/\/+$/, '')
45
45
 
46
- // Cache busting
47
- if (type !== 'path') {
48
- url.searchParams.set('_', Date.now())
49
- }
50
-
51
46
  // Handle other URL types
52
47
  if (url.pathname.includes('/_jcr_content/par')) {
53
48
  return normalizeReference(url, type)
@@ -77,7 +72,7 @@ function normalizePage(url, type) {
77
72
  url.pathname += '.html'
78
73
  }
79
74
 
80
- return type === 'path' ? url.pathname : url.href
75
+ return url
81
76
  }
82
77
 
83
78
  /**
@@ -98,7 +93,7 @@ function normalizeAsset(url, type) {
98
93
  throw new Error('Cant load content of an asset node')
99
94
  }
100
95
 
101
- return type === 'path' ? url.pathname : url.href
96
+ return url
102
97
  }
103
98
 
104
99
  /**
@@ -118,7 +113,7 @@ function normalizeReference(url, type) {
118
113
  throw new Error('Cant load children of a reference node')
119
114
  }
120
115
 
121
- return url.href
116
+ return url
122
117
  }
123
118
 
124
119
  // Default export
@@ -0,0 +1,90 @@
1
+ const normalize = require('./normalize')
2
+ const crossFetch = require('cross-fetch')
3
+ const Bottleneck = require('bottleneck/light.js')
4
+
5
+ /**
6
+ * Default limiter options
7
+ * @see https://stackleap.io/js/bottleneck#user-content-constructor
8
+ * @const {object}
9
+ * @private
10
+ */
11
+ const limiterOptions = {
12
+ reservoir: 150,
13
+ reservoirRefreshAmount: 150,
14
+ reservoirRefreshInterval: 5000,
15
+ maxConcurrent: 10,
16
+ trackDoneStatus: true
17
+ }
18
+
19
+ /**
20
+ * Rate limiter
21
+ * @const {Bottleneck}
22
+ */
23
+ const limiter = new Bottleneck(limiterOptions)
24
+
25
+ /**
26
+ * Passthrough to prevent running method on non window object
27
+ * @param {string|URL} url
28
+ * @private
29
+ */
30
+ const pFetch = url => crossFetch(url)
31
+
32
+ /**
33
+ * Modified rate limited fetch
34
+ * @param {string|URL} url
35
+ * @param {object} [options] Fetch options
36
+ * @returns {Promise<Object>}
37
+ */
38
+ async function request(url) {
39
+
40
+ // Handle relative URLs
41
+ if (typeof url === 'string') {
42
+ url = new URL(url, normalize.baseURL)
43
+ }
44
+
45
+ // Set cache busting param
46
+ url.searchParams.set('_', Date.now())
47
+
48
+ let response = await limiter.schedule(pFetch, url)
49
+
50
+ // Verify response code
51
+ if (!response.ok) {
52
+ throw new Error(response.statusText)
53
+ }
54
+
55
+ // Verify destination
56
+ if (!response.url.startsWith(normalize.baseURL)) {
57
+ throw new Error('Invalid destination URL')
58
+ }
59
+
60
+ // Determine if path changed
61
+ let redirected = normalize(url).pathname !== normalize(response.url).pathname
62
+
63
+ // Format result
64
+ return {
65
+ url: response.url,
66
+ redirected: redirected,
67
+ data: await responseData(response),
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Get data of the response by type
73
+ * @param {Response} response
74
+ * @returns {Promise<any>}
75
+ * @private
76
+ */
77
+ async function responseData(response) {
78
+ const contentType = response.headers.get('content-type')
79
+
80
+ // Parse JSON
81
+ if (contentType.includes('application/json')) {
82
+ return response.json()
83
+ }
84
+
85
+ return response.text()
86
+ }
87
+
88
+ // Exports
89
+ module.exports = exports = request
90
+ exports.limiter = limiter
package/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
- const fetch = require('./fetch.js')
2
- const normalize = require('./normalize.js')
3
- const children = require('./children.js')
4
- const content = require('./content.js')
5
- const meta = require('./meta.js')
1
+ const request = require('./core/request.js')
2
+ const normalize = require('./core/normalize.js')
3
+ const children = require('./basic/children.js')
4
+ const content = require('./basic/content.js')
5
+ const meta = require('./basic/meta.js')
6
6
 
7
7
  module.exports = exports = {
8
8
  // Core
9
- fetch,
9
+ request,
10
10
  normalize,
11
11
 
12
12
  // Basic API
package/src/children.js DELETED
@@ -1,55 +0,0 @@
1
- const normalize = require('./normalize.js')
2
- const merge = require('merge-options')
3
- const fetch = require('./fetch.js')
4
-
5
- /**
6
- * Default fetch options
7
- * @const {object}
8
- * @private
9
- */
10
- const defaultOptions = {
11
- jobOptions: {
12
- priority: 0
13
- },
14
- rawContent: false
15
- }
16
-
17
- /**
18
- * Get list of child nodes from sitemap
19
- * @param {string} url node url
20
- * @param {Object} [options] fetch options
21
- * @returns {Promise<Array>}
22
- */
23
- const children = async (url, options) => {
24
- url = normalize(url, 'children')
25
- options = merge(defaultOptions, options)
26
-
27
- let response = await fetch(url, options)
28
- let xml = await response.text()
29
-
30
- // Return raw text
31
- if (options.rawContent) {
32
- return xml
33
- }
34
-
35
- // Parse XML sitemap
36
- let children = xml.match(/<url>.*?<\/url>/g).map(url => {
37
- let loc = url.match(/<loc>([^<]+)<\/loc>/)
38
- let mod = url.match(/<lastmod>([^<]+)<\/lastmod>/)
39
-
40
- return {
41
- path: normalize(loc[1]),
42
- lastmod: mod ? Date.parse(mod[1]) : null
43
- }
44
- })
45
-
46
- // First entry may be the parent
47
- if (children.length && children[0].path === normalize(url)) {
48
- children.shift()
49
- }
50
-
51
- return children
52
- }
53
-
54
- // Default export
55
- module.exports = exports = children
package/src/content.js DELETED
@@ -1,48 +0,0 @@
1
- const normalize = require('./normalize.js')
2
- const merge = require('merge-options')
3
- const fetch = require('./fetch.js')
4
-
5
- /**
6
- * Default fetch options
7
- * @const {object}
8
- * @private
9
- */
10
- const defaultOptions = {
11
- rawContent: false
12
- }
13
-
14
- /**
15
- * Get node content
16
- * @param {string} url node URL
17
- * @param {Object} [options] fetch options
18
- * @returns {Promise<any>}
19
- */
20
- const content = async (url, options = {}) => {
21
- url = normalize(url, 'content')
22
- options = merge(defaultOptions, options)
23
-
24
- let response = await fetch(url, options)
25
-
26
- // Return raw text
27
- if (options.rawContent) {
28
- return await response.text()
29
- }
30
-
31
- let type = response.headers.get('Content-Type')
32
-
33
- if (type.includes('/json')) {
34
- return response.json()
35
- }
36
-
37
- let text = await response.text()
38
-
39
- // Compress whitespace in html
40
- if (type.includes('text/html')) {
41
- text = text.replace(/\s+/g, ' ')
42
- }
43
-
44
- return text
45
- }
46
-
47
- // Default export
48
- module.exports = exports = content
package/src/fetch.js DELETED
@@ -1,60 +0,0 @@
1
- const baseURL = require('./normalize').baseURL
2
- const crossFetch = require('cross-fetch')
3
- const Bottleneck = require('bottleneck/light.js')
4
-
5
- /**
6
- * Default limiter options
7
- * @see https://stackleap.io/js/bottleneck#user-content-constructor
8
- * @const {object}
9
- * @private
10
- */
11
- const limiterOptions = {
12
- reservoir: 150,
13
- reservoirRefreshAmount: 150,
14
- reservoirRefreshInterval: 5000,
15
- maxConcurrent: 10,
16
- trackDoneStatus: true
17
- }
18
-
19
- /**
20
- * Rate limiter
21
- * @const {Bottleneck}
22
- */
23
- const limiter = new Bottleneck(limiterOptions)
24
-
25
- /**
26
- * Passthrough arguments to prevent running method on non window object
27
- * @param {string|URL} url
28
- * @param {object} [options] Fetch options
29
- * @private
30
- */
31
- const pFetch = (url, options) => crossFetch(url, options)
32
-
33
- /**
34
- * Modified rate limited fetch
35
- * @param {string|URL} url
36
- * @param {object} [options] Fetch options
37
- * @returns {Promise<Response>}
38
- */
39
- const fetch = async (url, options) => {
40
- let jobOptions = options?.jobOptions || {}
41
- let response = await limiter.schedule(jobOptions, pFetch, url, options)
42
-
43
- // Verify response code
44
- if (!response.ok) {
45
- throw new Error(response.statusText)
46
- }
47
-
48
- // Verify destination
49
- if (!response.url.startsWith(baseURL)) {
50
- throw new Error('Invalid destination URL')
51
- }
52
-
53
- return response
54
- }
55
-
56
- // Default export
57
- module.exports = exports = fetch
58
-
59
- // Expose the limiter
60
- exports.limiter = limiter
package/src/meta.js DELETED
@@ -1,95 +0,0 @@
1
- const normalize = require('./normalize.js')
2
- const merge = require('merge-options')
3
- const fetch = require('./fetch.js')
4
-
5
- /**
6
- * Default fetch options
7
- * @const {object}
8
- * @private
9
- */
10
- const defaultOptions = {
11
- jobOptions: {
12
- expiration: 30000
13
- },
14
- rawContent: false
15
- }
16
-
17
- /**
18
- * Get node metadata from jcr content
19
- * @param {string} url node path
20
- * @param {Object} [options] fetch options
21
- * @returns {Promise<Object>}
22
- */
23
- const meta = async (url, options) => {
24
- url = normalize(url, 'meta')
25
- options = merge(defaultOptions, options)
26
-
27
- let response = await fetch(url, options)
28
-
29
- // Return raw text
30
- if (options.rawContent) {
31
- return await response.text()
32
- }
33
-
34
- // Verify content-type
35
- if (!response.headers.get('content-type').includes('application/json')) {
36
- throw new Error('Unexpected response content-type')
37
- }
38
-
39
- let json = await response.json()
40
-
41
- // Format meta properties
42
- Object.keys(json).forEach(key => {
43
- if (json[key] === 'true') {
44
- json[key] = true
45
- } else if (json[key] === 'false') {
46
- json[key] = false
47
- } else if (key.endsWith('@TypeHint')) {
48
- delete json[key]
49
- } else if (typeof json[key] === 'string') {
50
- json[key] = maybeParseDate(json[key])
51
- } else if (Array.isArray(json[key]) && json[key].length === 0) {
52
- delete json[key]
53
- }
54
- })
55
-
56
- // Sort object keys alphabetically for readability
57
- return Object.keys(json).sort().reduce((obj, key) => {
58
- obj[key] = json[key]
59
- return obj
60
- }, {})
61
- }
62
-
63
- /**
64
- * Map month name to number
65
- * @const {object}
66
- * @private
67
- */
68
- const months = {
69
- 'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
70
- 'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'
71
- }
72
-
73
- /**
74
- * Try to parse a date
75
- * @param {string} date
76
- * @returns {number|string}
77
- * @private
78
- */
79
- function maybeParseDate(date) {
80
- // Simple
81
- if (/^\d{4}-\d{2}-\d{2}$/.test(date)) {
82
- return Date.parse(date)
83
- }
84
-
85
- // RFC1123
86
- let m = /^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(date)
87
- if (m) {
88
- return Date.parse(m[3] + '-' + months[m[1]] + '-' + m[2] + 'T' + m[4] + m[5])
89
- }
90
-
91
- return date
92
- }
93
-
94
- // Default export
95
- module.exports = exports = meta